1 ;;; allout.el --- extensive outline mode for use alone and with other modes
3 ;; Copyright (C) 1992, 1993, 1994, 2001, 2002 Free Software Foundation, Inc.
5 ;; Author: Ken Manheimer <klm@zope.com>
6 ;; Maintainer: Ken Manheimer <klm@zope.com>
7 ;; Created: Dec 1991 - first release to usenet
8 ;; Keywords: outlines mode wp languages
10 ;; This file is part of GNU Emacs.
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
29 ;; Allout outline mode provides extensive outline formatting and
30 ;; and manipulation beyond standard emacs outline mode. It provides
31 ;; for structured editing of outlines, as well as navigation and
32 ;; exposure. It also provides for syntax-sensitive text like
33 ;; programming languages. (For an example, see the allout code
34 ;; itself, which is organized in ;; an outline framework.)
36 ;; In addition to outline navigation and exposure, allout includes:
38 ;; - topic-oriented repositioning, cut, and paste
39 ;; - integral outline exposure-layout
40 ;; - incremental search with dynamic exposure and reconcealment of hidden text
41 ;; - automatic topic-number maintenance
42 ;; - "Hot-spot" operation, for single-keystroke maneuvering and
43 ;; exposure control. (See the `allout-mode' docstring.)
45 ;; and many other features.
47 ;; The outline menubar additions provide quick reference to many of
48 ;; the features, and see the docstring of the function `allout-init'
49 ;; for instructions on priming your emacs session for automatic
50 ;; activation of `allout-mode'.
52 ;; See the docstring of the variables `allout-layout' and
53 ;; `allout-auto-activation' for details on automatic activation of
54 ;; allout `allout-mode' as a minor mode. (It has changed since allout
55 ;; 3.x, for those of you that depend on the old method.)
57 ;; Note - the lines beginning with `;;;_' are outline topic headers.
58 ;; Just `ESC-x eval-current-buffer' to give it a whirl.
60 ;; Ken Manheimer klm@zope.com
67 ;;;_* USER CUSTOMIZATION VARIABLES:
69 "Extensive outline mode for use alone and with other modes."
73 ;;;_ + Layout, Mode, and Topic Header Configuration
75 ;;;_ = allout-auto-activation
76 (defcustom allout-auto-activation nil
77 "*Regulates auto-activation modality of allout outlines - see `allout-init'.
79 Setq-default by `allout-init' to regulate whether or not allout
80 outline mode is automatically activated when the buffer-specific
81 variable `allout-layout' is non-nil, and whether or not the layout
82 dictated by `allout-layout' should be imposed on mode activation.
84 With value t, auto-mode-activation and auto-layout are enabled.
85 \(This also depends on `allout-find-file-hook' being installed in
86 `find-file-hook', which is also done by `allout-init'.)
88 With value `ask', auto-mode-activation is enabled, and endorsement for
89 performing auto-layout is asked of the user each time.
91 With value `activate', only auto-mode-activation is enabled,
94 With value nil, neither auto-mode-activation nor auto-layout are
97 See the docstring for `allout-init' for the proper interface to
99 :type
'(choice (const :tag
"On" t
)
100 (const :tag
"Ask about layout" "ask")
101 (const :tag
"Mode only" "activate")
102 (const :tag
"Off" nil
))
105 (defvar allout-layout nil
106 "*Layout specification and provisional mode trigger for allout outlines.
110 A list value specifies a default layout for the current buffer, to be
111 applied upon activation of `allout-mode'. Any non-nil value will
112 automatically trigger `allout-mode', provided `allout-init'
113 has been called to enable it.
115 See the docstring for `allout-init' for details on setting up for
116 auto-mode-activation, and for `allout-expose-topic' for the format of
117 the layout specification.
119 You can associate a particular outline layout with a file by setting
120 this var via the file's local variables. For example, the following
121 lines at the bottom of an Emacs Lisp file:
124 ;;;allout-layout: \(0 : -1 -1 0)
127 will, modulo the above-mentioned conditions, cause the mode to be
128 activated when the file is visited, followed by the equivalent of
129 `\(allout-expose-topic 0 : -1 -1 0)'. \(This is the layout used for
130 the allout.el, itself.)
132 Also, allout's mode-specific provisions will make topic prefixes default
133 to the comment-start string, if any, of the language of the file. This
134 is modulo the setting of `allout-use-mode-specific-leader', which see.")
135 (make-variable-buffer-local 'allout-layout
)
136 ;;;_ = allout-show-bodies
137 (defcustom allout-show-bodies nil
138 "*If non-nil, show entire body when exposing a topic, rather than
142 (make-variable-buffer-local 'allout-show-bodies
)
144 ;;;_ = allout-header-prefix
145 (defcustom allout-header-prefix
"."
146 "*Leading string which helps distinguish topic headers.
148 Outline topic header lines are identified by a leading topic
149 header prefix, which mostly have the value of this var at their front.
150 \(Level 1 topics are exceptions. They consist of only a single
151 character, which is typically set to the `allout-primary-bullet'. Many
152 outlines start at level 2 to avoid this discrepancy."
155 (make-variable-buffer-local 'allout-header-prefix
)
156 ;;;_ = allout-primary-bullet
157 (defcustom allout-primary-bullet
"*"
158 "Bullet used for top-level outline topics.
160 Outline topic header lines are identified by a leading topic header
161 prefix, which is concluded by bullets that includes the value of this
162 var and the respective allout-*-bullets-string vars.
164 The value of an asterisk (`*') provides for backwards compatibility
165 with the original emacs outline mode. See `allout-plain-bullets-string'
166 and `allout-distinctive-bullets-string' for the range of available
170 (make-variable-buffer-local 'allout-primary-bullet
)
171 ;;;_ = allout-plain-bullets-string
172 (defcustom allout-plain-bullets-string
".:,;"
173 "*The bullets normally used in outline topic prefixes.
175 See `allout-distinctive-bullets-string' for the other kind of
178 DO NOT include the close-square-bracket, `]', as a bullet.
180 Outline mode has to be reactivated in order for changes to the value
181 of this var to take effect."
184 (make-variable-buffer-local 'allout-plain-bullets-string
)
185 ;;;_ = allout-distinctive-bullets-string
186 (defcustom allout-distinctive-bullets-string
"*+-=>([{}&!?#%\"X@$~_\\"
187 "*Persistent outline header bullets used to distinguish special topics.
189 These bullets are used to distinguish topics from the run-of-the-mill
190 ones. They are not used in the standard topic headers created by
191 the topic-opening, shifting, and rebulleting \(eg, on topic shift,
192 topic paste, blanket rebulleting) routines, but are offered among the
193 choices for rebulleting. They are not altered by the above automatic
194 rebulleting, so they can be used to characterize topics, eg:
197 `\(' parenthetic comment \(with a matching close paren inside)
198 `[' meta-note \(with a matching close ] inside)
203 ... just for example. (`#' typically has a special meaning to the
204 software, according to the value of `allout-numbered-bullet'.)
206 See `allout-plain-bullets-string' for the selection of
209 You must run `set-allout-regexp' in order for outline mode to
210 reconcile to changes of this value.
212 DO NOT include the close-square-bracket, `]', on either of the bullet
216 (make-variable-buffer-local 'allout-distinctive-bullets-string
)
218 ;;;_ = allout-use-mode-specific-leader
219 (defcustom allout-use-mode-specific-leader t
220 "*When non-nil, use mode-specific topic-header prefixes.
222 Allout outline mode will use the mode-specific `allout-mode-leaders'
223 and/or comment-start string, if any, to lead the topic prefix string,
224 so topic headers look like comments in the programming language.
226 String values are used as they stand.
228 Value t means to first check for assoc value in `allout-mode-leaders'
229 alist, then use comment-start string, if any, then use default \(`.').
230 \(See note about use of comment-start strings, below.)
232 Set to the symbol for either of `allout-mode-leaders' or
233 `comment-start' to use only one of them, respectively.
235 Value nil means to always use the default \(`.').
237 comment-start strings that do not end in spaces are tripled, and an
238 `_' underscore is tacked on the end, to distinguish them from regular
239 comment strings. comment-start strings that do end in spaces are not
240 tripled, but an underscore is substituted for the space. [This
241 presumes that the space is for appearance, not comment syntax. You
242 can use `allout-mode-leaders' to override this behavior, when
244 :type
'(choice (const t
) (const nil
) string
245 (const allout-mode-leaders
)
246 (const comment-start
))
248 ;;;_ = allout-mode-leaders
249 (defvar allout-mode-leaders
'()
250 "Specific allout-prefix leading strings per major modes.
252 Entries will be used instead or in lieu of mode-specific
253 comment-start strings. See also `allout-use-mode-specific-leader'.
255 If you're constructing a string that will comment-out outline
256 structuring so it can be included in program code, append an extra
257 character, like an \"_\" underscore, to distinguish the lead string
258 from regular comments that start at bol.")
260 ;;;_ = allout-old-style-prefixes
261 (defcustom allout-old-style-prefixes nil
262 "*When non-nil, use only old-and-crusty `outline-mode' `*' topic prefixes.
264 Non-nil restricts the topic creation and modification
265 functions to asterix-padded prefixes, so they look exactly
266 like the original emacs-outline style prefixes.
268 Whatever the setting of this variable, both old and new style prefixes
269 are always respected by the topic maneuvering functions."
272 (make-variable-buffer-local 'allout-old-style-prefixes
)
273 ;;;_ = allout-stylish-prefixes - alternating bullets
274 (defcustom allout-stylish-prefixes t
275 "*Do fancy stuff with topic prefix bullets according to level, etc.
277 Non-nil enables topic creation, modification, and repositioning
278 functions to vary the topic bullet char (the char that marks the topic
279 depth) just preceding the start of the topic text) according to level.
280 Otherwise, only asterisks (`*') and distinctive bullets are used.
282 This is how an outline can look (but sans indentation) with stylish
287 . + One level 3 subtopic
288 . . One level 4 subtopic
289 . . A second 4 subtopic
290 . + Another level 3 subtopic
291 . #1 A numbered level 4 subtopic
293 . ! Another level 4 subtopic with a different distinctive bullet
294 . #4 And another numbered level 4 subtopic
296 This would be an outline with stylish prefixes inhibited (but the
297 numbered and other distinctive bullets retained):
301 . * One level 3 subtopic
302 . * One level 4 subtopic
303 . * A second 4 subtopic
304 . * Another level 3 subtopic
305 . #1 A numbered level 4 subtopic
307 . ! Another level 4 subtopic with a different distinctive bullet
308 . #4 And another numbered level 4 subtopic
310 Stylish and constant prefixes (as well as old-style prefixes) are
311 always respected by the topic maneuvering functions, regardless of
312 this variable setting.
314 The setting of this var is not relevant when `allout-old-style-prefixes'
318 (make-variable-buffer-local 'allout-stylish-prefixes
)
320 ;;;_ = allout-numbered-bullet
321 (defcustom allout-numbered-bullet
"#"
322 "*String designating bullet of topics that have auto-numbering; nil for none.
324 Topics having this bullet have automatic maintenance of a sibling
325 sequence-number tacked on, just after the bullet. Conventionally set
326 to \"#\", you can set it to a bullet of your choice. A nil value
327 disables numbering maintenance."
328 :type
'(choice (const nil
) string
)
330 (make-variable-buffer-local 'allout-numbered-bullet
)
331 ;;;_ = allout-file-xref-bullet
332 (defcustom allout-file-xref-bullet
"@"
333 "*Bullet signifying file cross-references, for `allout-resolve-xref'.
335 Set this var to the bullet you want to use for file cross-references."
336 :type
'(choice (const nil
) string
)
339 ;;;_ = allout-presentation-padding
340 (defcustom allout-presentation-padding
2
341 "*Presentation-format white-space padding factor, for greater indent."
345 (make-variable-buffer-local 'allout-presentation-padding
)
347 ;;;_ = allout-abbreviate-flattened-numbering
348 (defcustom allout-abbreviate-flattened-numbering nil
349 "*If non-nil, `allout-flatten-exposed-to-buffer' abbreviates topic
350 numbers to minimal amount with some context. Otherwise, entire
351 numbers are always used."
355 ;;;_ + LaTeX formatting
356 ;;;_ - allout-number-pages
357 (defcustom allout-number-pages nil
358 "*Non-nil turns on page numbering for LaTeX formatting of an outline."
361 ;;;_ - allout-label-style
362 (defcustom allout-label-style
"\\large\\bf"
363 "*Font and size of labels for LaTeX formatting of an outline."
366 ;;;_ - allout-head-line-style
367 (defcustom allout-head-line-style
"\\large\\sl "
368 "*Font and size of entries for LaTeX formatting of an outline."
371 ;;;_ - allout-body-line-style
372 (defcustom allout-body-line-style
" "
373 "*Font and size of entries for LaTeX formatting of an outline."
376 ;;;_ - allout-title-style
377 (defcustom allout-title-style
"\\Large\\bf"
378 "*Font and size of titles for LaTeX formatting of an outline."
382 (defcustom allout-title
'(or buffer-file-name
(current-buffer-name))
383 "*Expression to be evaluated to determine the title for LaTeX
387 ;;;_ - allout-line-skip
388 (defcustom allout-line-skip
".05cm"
389 "*Space between lines for LaTeX formatting of an outline."
393 (defcustom allout-indent
".3cm"
394 "*LaTeX formatted depth-indent spacing."
398 ;;;_ + Miscellaneous customization
400 ;;;_ = allout-command-prefix
401 (defcustom allout-command-prefix
"\C-c"
402 "*Key sequence to be used as prefix for outline mode command key bindings."
406 ;;;_ = allout-keybindings-list
407 ;;; You have to reactivate allout-mode - `(allout-mode t)' - to
408 ;;; institute changes to this var.
409 (defvar allout-keybindings-list
()
410 "*List of `allout-mode' key / function bindings, for `allout-mode-map'.
412 String or vector key will be prefaced with `allout-command-prefix',
413 unless optional third, non-nil element is present.")
414 (setq allout-keybindings-list
417 ("\C-n" allout-next-visible-heading
)
418 ("\C-p" allout-previous-visible-heading
)
419 ("\C-u" allout-up-current-level
)
420 ("\C-f" allout-forward-current-level
)
421 ("\C-b" allout-backward-current-level
)
422 ("\C-a" allout-beginning-of-current-entry
)
423 ("\C-e" allout-end-of-current-entry
)
425 ("\C-i" allout-show-children
)
426 ("\C-s" allout-show-current-subtree
)
427 ("\C-h" allout-hide-current-subtree
)
428 ("\C-o" allout-show-current-entry
)
429 ("!" allout-show-all
)
430 ; Alteration commands:
431 (" " allout-open-sibtopic
)
432 ("." allout-open-subtopic
)
433 ("," allout-open-supertopic
)
434 ("'" allout-shift-in
)
435 (">" allout-shift-in
)
436 ("<" allout-shift-out
)
437 ("\C-m" allout-rebullet-topic
)
438 ("*" allout-rebullet-current-heading
)
439 ("#" allout-number-siblings
)
440 ("\C-k" allout-kill-line t
)
441 ("\C-y" allout-yank t
)
442 ("\M-y" allout-yank-pop t
)
443 ("\C-k" allout-kill-topic
)
444 ; Miscellaneous commands:
445 ;([?\C-\ ] allout-mark-topic)
446 ("@" allout-resolve-xref
)
447 ("=c" allout-copy-exposed-to-buffer
)
448 ("=i" allout-indented-exposed-to-buffer
)
449 ("=t" allout-latexify-exposed
)
450 ("=p" allout-flatten-exposed-to-buffer
)))
452 ;;;_ = allout-isearch-dynamic-expose
453 (defcustom allout-isearch-dynamic-expose t
454 "*Non-nil enable dynamic exposure of hidden incremental-search
455 targets as they're encountered."
458 (make-variable-buffer-local 'allout-isearch-dynamic-expose
)
460 ;;;_ = allout-use-hanging-indents
461 (defcustom allout-use-hanging-indents t
462 "*If non-nil, topic body text auto-indent defaults to indent of the header.
463 Ie, it is indented to be just past the header prefix. This is
464 relevant mostly for use with indented-text-mode, or other situations
465 where auto-fill occurs.
467 \[This feature no longer depends in any way on the `filladapt.el'
468 lisp-archive package.\]"
471 (make-variable-buffer-local 'allout-use-hanging-indents
)
473 ;;;_ = allout-reindent-bodies
474 (defcustom allout-reindent-bodies
(if allout-use-hanging-indents
476 "*Non-nil enables auto-adjust of topic body hanging indent with depth shifts.
478 When active, topic body lines that are indented even with or beyond
479 their topic header are reindented to correspond with depth shifts of
482 A value of t enables reindent in non-programming-code buffers, ie
483 those that do not have the variable `comment-start' set. A value of
484 `force' enables reindent whether or not `comment-start' is set."
485 :type
'(choice (const nil
) (const t
) (const text
) (const force
))
488 (make-variable-buffer-local 'allout-reindent-bodies
)
490 ;;;_ = allout-inhibit-protection
491 (defcustom allout-inhibit-protection nil
492 "*Non-nil disables warnings and confirmation-checks for concealed-text edits.
494 Outline mode uses emacs change-triggered functions to detect unruly
495 changes to concealed regions. Set this var non-nil to disable the
496 protection, potentially increasing text-entry responsiveness a bit.
498 This var takes effect at `allout-mode' activation, so you may have to
499 deactivate and then reactivate the mode if you want to toggle the
504 ;;;_* CODE - no user customizations below.
506 ;;;_ #1 Internal Outline Formatting and Configuration
508 ;;;_ = allout-version
509 (defvar allout-version
510 (let ((rcs-rev "$Revision: 1.48 $"))
513 (string-match "Revision: \\([0-9]+\\.[0-9]+\\)" rcs-rev
)
514 (substring rcs-rev
(match-beginning 1) (match-end 1)))
516 "Revision number of currently loaded outline package. \(allout.el)")
517 ;;;_ > allout-version
518 (defun allout-version (&optional here
)
519 "Return string describing the loaded outline version."
521 (let ((msg (concat "Allout Outline Mode v " allout-version
)))
522 (if here
(insert msg
))
525 ;;;_ : Topic header format
527 (defvar allout-regexp
""
528 "*Regular expression to match the beginning of a heading line.
530 Any line whose beginning matches this regexp is considered a
531 heading. This var is set according to the user configuration vars
532 by `set-allout-regexp'.")
533 (make-variable-buffer-local 'allout-regexp
)
534 ;;;_ = allout-bullets-string
535 (defvar allout-bullets-string
""
536 "A string dictating the valid set of outline topic bullets.
538 This var should *not* be set by the user - it is set by `set-allout-regexp',
539 and is produced from the elements of `allout-plain-bullets-string'
540 and `allout-distinctive-bullets-string'.")
541 (make-variable-buffer-local 'allout-bullets-string
)
542 ;;;_ = allout-bullets-string-len
543 (defvar allout-bullets-string-len
0
544 "Length of current buffers' `allout-plain-bullets-string'.")
545 (make-variable-buffer-local 'allout-bullets-string-len
)
546 ;;;_ = allout-line-boundary-regexp
547 (defvar allout-line-boundary-regexp
()
548 "`allout-regexp' with outline style beginning-of-line anchor.
550 \(Ie, C-j, *or* C-m, for prefixes of hidden topics). This is properly
551 set when `allout-regexp' is produced by `set-allout-regexp', so
552 that (match-beginning 2) and (match-end 2) delimit the prefix.")
553 (make-variable-buffer-local 'allout-line-boundary-regexp
)
554 ;;;_ = allout-bob-regexp
555 (defvar allout-bob-regexp
()
556 "Like `allout-line-boundary-regexp', for headers at beginning of buffer.
557 \(match-beginning 2) and \(match-end 2) delimit the prefix.")
558 (make-variable-buffer-local 'allout-bob-regexp
)
559 ;;;_ = allout-header-subtraction
560 (defvar allout-header-subtraction
(1- (length allout-header-prefix
))
561 "Allout-header prefix length to subtract when computing topic depth.")
562 (make-variable-buffer-local 'allout-header-subtraction
)
563 ;;;_ = allout-plain-bullets-string-len
564 (defvar allout-plain-bullets-string-len
(length allout-plain-bullets-string
)
565 "Length of `allout-plain-bullets-string', updated by `set-allout-regexp'.")
566 (make-variable-buffer-local 'allout-plain-bullets-string-len
)
569 ;;;_ X allout-reset-header-lead (header-lead)
570 (defun allout-reset-header-lead (header-lead)
571 "*Reset the leading string used to identify topic headers."
572 (interactive "sNew lead string: ")
573 (setq allout-header-prefix header-lead
)
574 (setq allout-header-subtraction
(1- (length allout-header-prefix
)))
576 ;;;_ X allout-lead-with-comment-string (header-lead)
577 (defun allout-lead-with-comment-string (&optional header-lead
)
578 "*Set the topic-header leading string to specified string.
580 Useful when for encapsulating outline structure in programming
581 language comments. Returns the leading string."
584 (if (not (stringp header-lead
))
585 (setq header-lead
(read-string
586 "String prefix for topic headers: ")))
587 (setq allout-reindent-bodies nil
)
588 (allout-reset-header-lead header-lead
)
590 ;;;_ > allout-infer-header-lead ()
591 (defun allout-infer-header-lead ()
592 "Determine appropriate `allout-header-prefix'.
594 Works according to settings of:
597 `allout-header-prefix' (default)
598 `allout-use-mode-specific-leader'
599 and `allout-mode-leaders'.
601 Apply this via \(re)activation of `allout-mode', rather than
602 invoking it directly."
603 (let* ((use-leader (and (boundp 'allout-use-mode-specific-leader
)
604 (if (or (stringp allout-use-mode-specific-leader
)
605 (memq allout-use-mode-specific-leader
606 '(allout-mode-leaders
609 allout-use-mode-specific-leader
610 ;; Oops - garbled value, equate with effect of 't:
614 ((not use-leader
) nil
)
615 ;; Use the explicitly designated leader:
616 ((stringp use-leader
) use-leader
)
617 (t (or (and (memq use-leader
'(t allout-mode-leaders
))
618 ;; Get it from outline mode leaders?
619 (cdr (assq major-mode allout-mode-leaders
)))
620 ;; ... didn't get from allout-mode-leaders...
621 (and (memq use-leader
'(t comment-start
))
623 ;; Use comment-start, maybe tripled, and with
627 (substring comment-start
628 (1- (length comment-start
))))
629 ;; Use comment-start, sans trailing space:
630 (substring comment-start
0 -
1)
631 (concat comment-start comment-start comment-start
))
632 ;; ... and append underscore, whichever:
636 (if (string= leader allout-header-prefix
)
637 nil
; no change, nothing to do.
638 (setq allout-header-prefix leader
)
639 allout-header-prefix
))))
640 ;;;_ > allout-infer-body-reindent ()
641 (defun allout-infer-body-reindent ()
642 "Determine proper setting for `allout-reindent-bodies'.
644 Depends on default setting of `allout-reindent-bodies' \(which see)
645 and presence of setting for `comment-start', to tell whether the
646 file is programming code."
647 (if (and allout-reindent-bodies
649 (not (eq 'force allout-reindent-bodies
)))
650 (setq allout-reindent-bodies nil
)))
651 ;;;_ > set-allout-regexp ()
652 (defun set-allout-regexp ()
653 "Generate proper topic-header regexp form for outline functions.
655 Works with respect to `allout-plain-bullets-string' and
656 `allout-distinctive-bullets-string'."
659 ;; Derive allout-bullets-string from user configured components:
660 (setq allout-bullets-string
"")
661 (let ((strings (list 'allout-plain-bullets-string
662 'allout-distinctive-bullets-string
663 'allout-primary-bullet
))
671 (setq new-string
"") (setq index
0)
672 (setq cur-len
(length (setq cur-string
(symbol-value (car strings
)))))
673 (while (< index cur-len
)
674 (setq cur-char
(aref cur-string index
))
675 (setq allout-bullets-string
676 (concat allout-bullets-string
678 ; Single dash would denote a
679 ; sequence, repeated denotes
681 ((eq cur-char ?-
) "--")
682 ; literal close-square-bracket
683 ; doesn't work right in the
685 ((eq cur-char ?\
]) "")
686 (t (regexp-quote (char-to-string cur-char
))))))
687 (setq index
(1+ index
)))
688 (setq strings
(cdr strings
)))
690 ;; Derive next for repeated use in allout-pending-bullet:
691 (setq allout-plain-bullets-string-len
(length allout-plain-bullets-string
))
692 (setq allout-header-subtraction
(1- (length allout-header-prefix
)))
693 ;; Produce the new allout-regexp:
694 (setq allout-regexp
(concat "\\(\\"
697 allout-bullets-string
699 allout-primary-bullet
701 (setq allout-line-boundary-regexp
702 (concat "\\([\n\r]\\)\\(" allout-regexp
"\\)"))
703 (setq allout-bob-regexp
704 (concat "\\(\\`\\)\\(" allout-regexp
"\\)"))
707 ;;;_ = allout-mode-map
708 (defvar allout-mode-map nil
"Keybindings for (allout) outline minor mode.")
709 ;;;_ > produce-allout-mode-map (keymap-alist &optional base-map)
710 (defun produce-allout-mode-map (keymap-list &optional base-map
)
711 "Produce keymap for use as allout-mode-map, from keymap-list.
713 Built on top of optional BASE-MAP, or empty sparse map if none specified.
714 See doc string for allout-keybindings-list for format of binding list."
715 (let ((map (or base-map
(make-sparse-keymap)))
716 (pref (list allout-command-prefix
)))
719 (let ((add-pref (null (cdr (cdr cell
))))
720 (key-suff (list (car cell
))))
723 (apply 'concat
(if add-pref
724 (append pref key-suff
)
726 (car (cdr cell
)))))))
731 (defvar allout-mode-exposure-menu
)
732 (defvar allout-mode-editing-menu
)
733 (defvar allout-mode-navigation-menu
)
734 (defvar allout-mode-misc-menu
)
735 (defun produce-allout-mode-menubar-entries ()
737 (easy-menu-define allout-mode-exposure-menu
739 "Allout outline exposure menu."
741 ["Show Entry" allout-show-current-entry t
]
742 ["Show Children" allout-show-children t
]
743 ["Show Subtree" allout-show-current-subtree t
]
744 ["Hide Subtree" allout-hide-current-subtree t
]
745 ["Hide Leaves" allout-hide-current-leaves t
]
747 ["Show All" allout-show-all t
]))
748 (easy-menu-define allout-mode-editing-menu
750 "Allout outline editing menu."
752 ["Open Sibling" allout-open-sibtopic t
]
753 ["Open Subtopic" allout-open-subtopic t
]
754 ["Open Supertopic" allout-open-supertopic t
]
756 ["Shift Topic In" allout-shift-in t
]
757 ["Shift Topic Out" allout-shift-out t
]
758 ["Rebullet Topic" allout-rebullet-topic t
]
759 ["Rebullet Heading" allout-rebullet-current-heading t
]
760 ["Number Siblings" allout-number-siblings t
]))
761 (easy-menu-define allout-mode-navigation-menu
763 "Allout outline navigation menu."
765 ["Next Visible Heading" allout-next-visible-heading t
]
766 ["Previous Visible Heading"
767 allout-previous-visible-heading t
]
769 ["Up Level" allout-up-current-level t
]
770 ["Forward Current Level" allout-forward-current-level t
]
771 ["Backward Current Level"
772 allout-backward-current-level t
]
774 ["Beginning of Entry"
775 allout-beginning-of-current-entry t
]
776 ["End of Entry" allout-end-of-current-entry t
]
777 ["End of Subtree" allout-end-of-current-subtree t
]))
778 (easy-menu-define allout-mode-misc-menu
780 "Allout outlines miscellaneous bindings."
782 ["Version" allout-version t
]
784 ["Duplicate Exposed" allout-copy-exposed-to-buffer t
]
785 ["Duplicate Exposed, numbered"
786 allout-flatten-exposed-to-buffer t
]
787 ["Duplicate Exposed, indented"
788 allout-indented-exposed-to-buffer t
]
790 ["Set Header Lead" allout-reset-header-lead t
]
791 ["Set New Exposure" allout-expose-topic t
])))
792 ;;;_ : Mode-Specific Variable Maintenance Utilities
793 ;;;_ = allout-mode-prior-settings
794 (defvar allout-mode-prior-settings nil
795 "Internal `allout-mode' use; settings to be resumed on mode deactivation.")
796 (make-variable-buffer-local 'allout-mode-prior-settings
)
797 ;;;_ > allout-resumptions (name &optional value)
798 (defun allout-resumptions (name &optional value
)
800 "Registers or resumes settings over `allout-mode' activation/deactivation.
802 First arg is NAME of variable affected. Optional second arg is list
803 containing allout-mode-specific VALUE to be imposed on named
804 variable, and to be registered. (It's a list so you can specify
805 registrations of null values.) If no value is specified, the
806 registered value is returned (encapsulated in the list, so the caller
807 can distinguish nil vs no value), and the registration is popped
810 (let ((on-list (assq name allout-mode-prior-settings
))
811 prior-capsule
; By `capsule' i mean a list
812 ; containing a value, so we can
813 ; distinguish nil from no value.
821 nil
; Already preserved prior value - don't mess with it.
822 ;; Register the old value, or nil if previously unbound:
823 (setq allout-mode-prior-settings
825 (if (boundp name
) (list (symbol-value name
))))
826 allout-mode-prior-settings
)))
827 ; And impose the new value, locally:
828 (progn (make-local-variable name
)
829 (set name
(car value
))))
834 ;; Oops, not registered - leave it be:
837 ;; Some registration:
839 (setq prior-capsule
(car (cdr on-list
)))
841 (set name
(car prior-capsule
)) ; Some prior value - reestablish it.
842 (makunbound name
)) ; Previously unbound - demolish var.
843 ; Remove registration:
845 (while allout-mode-prior-settings
846 (if (not (eq (car allout-mode-prior-settings
)
849 (cons (car allout-mode-prior-settings
)
851 (setq allout-mode-prior-settings
852 (cdr allout-mode-prior-settings
)))
853 (setq allout-mode-prior-settings rebuild
)))))
855 ;;;_ : Mode-specific incidentals
856 ;;;_ = allout-during-write-cue nil
857 (defvar allout-during-write-cue nil
858 "Used to inhibit outline change-protection during file write.
860 See also `allout-post-command-business', `allout-write-file-hook',
861 `allout-before-change-protect', and `allout-post-command-business'
863 ;;;_ = allout-pre-was-isearching nil
864 (defvar allout-pre-was-isearching nil
865 "Cue for isearch-dynamic-exposure mechanism, implemented in
866 allout-pre- and -post-command-hooks.")
867 (make-variable-buffer-local 'allout-pre-was-isearching
)
868 ;;;_ = allout-isearch-prior-pos nil
869 (defvar allout-isearch-prior-pos nil
870 "Cue for isearch-dynamic-exposure tracking, used by allout-isearch-expose.")
871 (make-variable-buffer-local 'allout-isearch-prior-pos
)
872 ;;;_ = allout-isearch-did-quit
873 (defvar allout-isearch-did-quit nil
874 "Distinguishes isearch conclusion and cancellation.
876 Maintained by `allout-isearch-abort' \(which is wrapped around the real
877 isearch-abort), and monitored by `allout-isearch-expose' for action.")
878 (make-variable-buffer-local 'allout-isearch-did-quit
)
879 ;;;_ = allout-override-protect nil
880 (defvar allout-override-protect nil
881 "Used in `allout-mode' for regulate of concealed-text protection mechanism.
883 Allout outline mode regulates alteration of concealed text to protect
884 against inadvertent, unnoticed changes. This is for use by specific,
885 native outline functions to temporarily override that protection.
886 It's automatically reset to nil after every buffer modification.")
887 (make-variable-buffer-local 'allout-override-protect
)
888 ;;;_ > allout-unprotected (expr)
889 (defmacro allout-unprotected
(expr)
890 "Evaluate EXPRESSION with `allout-override-protect' let-bound t."
891 `(let ((allout-override-protect t
))
893 ;;;_ = allout-undo-aggregation
894 (defvar allout-undo-aggregation
30
895 "Amount of successive self-insert actions to bunch together per undo.
897 This is purely a kludge variable, regulating the compensation for a bug in
898 the way that before-change-functions and undo interact.")
899 (make-variable-buffer-local 'allout-undo-aggregation
)
900 ;;;_ = file-var-bug hack
901 (defvar allout-v18
/19-file-var-hack nil
902 "Horrible hack used to prevent invalid multiple triggering of outline
903 mode from prop-line file-var activation. Used by `allout-mode' function
905 ;;;_ > allout-write-file-hook ()
906 (defun allout-write-file-hook ()
907 "In `allout-mode', run as a `write-contents-functions' activity.
909 Currently just sets `allout-during-write-cue', so outline change-protection
910 knows to keep inactive during file write."
911 (setq allout-during-write-cue t
)
914 ;;;_ #2 Mode activation
916 (defvar allout-mode
() "Allout outline mode minor-mode flag.")
917 (make-variable-buffer-local 'allout-mode
)
918 ;;;_ > allout-mode-p ()
919 (defmacro allout-mode-p
()
920 "Return t if `allout-mode' is active in current buffer."
922 ;;;_ = allout-explicitly-deactivated
923 (defvar allout-explicitly-deactivated nil
924 "Non-nil if `allout-mode' was last deliberately deactivated.
925 So `allout-post-command-business' should not reactivate it...")
926 (make-variable-buffer-local 'allout-explicitly-deactivated
)
927 ;;;_ > allout-init (&optional mode)
929 (defun allout-init (&optional mode
)
930 "Prime `allout-mode' to enable/disable auto-activation, wrt `allout-layout'.
932 MODE is one of the following symbols:
934 - nil \(or no argument) deactivate auto-activation/layout;
935 - `activate', enable auto-activation only;
936 - `ask', enable auto-activation, and enable auto-layout but with
937 confirmation for layout operation solicited from user each time;
938 - `report', just report and return the current auto-activation state;
939 - anything else \(eg, t) for auto-activation and auto-layout, without
940 any confirmation check.
942 Use this function to setup your emacs session for automatic activation
943 of allout outline mode, contingent to the buffer-specific setting of
944 the `allout-layout' variable. (See `allout-layout' and
945 `allout-expose-topic' docstrings for more details on auto layout).
947 `allout-init' works by setting up (or removing)
948 `allout-find-file-hook' in `find-file-hook', and giving
949 `allout-auto-activation' a suitable setting.
951 To prime your emacs session for full auto-outline operation, include
952 the following two lines in your emacs init file:
962 (concat "Select outline auto setup mode "
963 "(empty for report, ? for options) ")
964 '(("nil")("full")("activate")("deactivate")
965 ("ask") ("report") (""))
968 (if (string= mode
"")
970 (setq mode
(intern-soft mode
)))))
972 ;; convenience aliases, for consistent ref to respective vars:
973 ((hook 'allout-find-file-hook
)
974 (curr-mode 'allout-auto-activation
))
977 (setq find-file-hook
(delq hook find-file-hook
))
979 (message "Allout outline mode auto-activation inhibited.")))
981 (if (memq hook find-file-hook
)
982 ;; Just punt and use the reports from each of the modes:
983 (allout-init (symbol-value curr-mode
))
985 (message "Allout outline mode auto-activation inhibited.")))
986 (t (add-hook 'find-file-hook hook
)
987 (set curr-mode
; `set', not `setq'!
988 (cond ((eq mode
'activate
)
990 "Outline mode auto-activation enabled.")
993 ;; Return the current mode setting:
997 (concat "Outline mode auto-activation and "
998 "-layout \(upon confirmation) enabled."))
1001 "Outline mode auto-activation and -layout enabled.")
1004 ;;;_ > allout-setup-menubar ()
1005 (defun allout-setup-menubar ()
1006 "Populate the current buffer's menubar with `allout-mode' stuff."
1007 (let ((menus (list allout-mode-exposure-menu
1008 allout-mode-editing-menu
1009 allout-mode-navigation-menu
1010 allout-mode-misc-menu
))
1013 (setq cur
(car menus
)
1015 (easy-menu-add cur
))))
1016 ;;;_ > allout-mode (&optional toggle)
1018 (defun allout-mode (&optional toggle
)
1020 "Toggle minor mode for controlling exposure and editing of text outlines.
1022 Optional arg forces mode to re-initialize iff arg is positive num or
1023 symbol. Allout outline mode always runs as a minor mode.
1025 Allout outline mode provides extensive outline oriented formatting and
1026 manipulation. It enables structural editing of outlines, as well as
1027 navigation and exposure. It also is specifically aimed at
1028 accommodating syntax-sensitive text like programming languages. \(For
1029 an example, see the allout code itself, which is organized as an allout
1032 In addition to outline navigation and exposure, allout includes:
1034 - topic-oriented repositioning, cut, and paste
1035 - integral outline exposure-layout
1036 - incremental search with dynamic exposure and reconcealment of hidden text
1037 - automatic topic-number maintenance
1038 - \"Hot-spot\" operation, for single-keystroke maneuvering and
1039 exposure control. \(See the allout-mode docstring.)
1041 and many other features.
1043 Below is a description of the bindings, and then explanation of
1044 special `allout-mode' features and terminology. See also the outline
1045 menubar additions for quick reference to many of the features, and see
1046 the docstring of the function `allout-init' for instructions on
1047 priming your emacs session for automatic activation of `allout-mode'.
1050 The bindings are dictated by the `allout-keybindings-list' and
1051 `allout-command-prefix' variables.
1053 Navigation: Exposure Control:
1054 ---------- ----------------
1055 C-c C-n allout-next-visible-heading | C-c C-h allout-hide-current-subtree
1056 C-c C-p allout-previous-visible-heading | C-c C-i allout-show-children
1057 C-c C-u allout-up-current-level | C-c C-s allout-show-current-subtree
1058 C-c C-f allout-forward-current-level | C-c C-o allout-show-current-entry
1059 C-c C-b allout-backward-current-level | ^U C-c C-s allout-show-all
1060 C-c C-e allout-end-of-current-entry | allout-hide-current-leaves
1061 C-c C-a allout-beginning-of-current-entry, alternately, goes to hot-spot
1063 Topic Header Production:
1064 -----------------------
1065 C-c<SP> allout-open-sibtopic Create a new sibling after current topic.
1066 C-c . allout-open-subtopic ... an offspring of current topic.
1067 C-c , allout-open-supertopic ... a sibling of the current topic's parent.
1069 Topic Level and Prefix Adjustment:
1070 ---------------------------------
1071 C-c > allout-shift-in Shift current topic and all offspring deeper.
1072 C-c < allout-shift-out ... less deep.
1073 C-c<CR> allout-rebullet-topic Reconcile bullets of topic and its offspring
1074 - distinctive bullets are not changed, others
1075 alternated according to nesting depth.
1076 C-c * allout-rebullet-current-heading Prompt for alternate bullet for
1078 C-c # allout-number-siblings Number bullets of topic and siblings - the
1079 offspring are not affected. With repeat
1080 count, revoke numbering.
1082 Topic-oriented Killing and Yanking:
1083 ----------------------------------
1084 C-c C-k allout-kill-topic Kill current topic, including offspring.
1085 C-k allout-kill-line Like kill-line, but reconciles numbering, etc.
1086 C-y allout-yank Yank, adjusting depth of yanked topic to
1087 depth of heading if yanking into bare topic
1088 heading (ie, prefix sans text).
1089 M-y allout-yank-pop Is to allout-yank as yank-pop is to yank
1093 M-x outlineify-sticky Activate outline mode for current buffer,
1094 and establish a default file-var setting
1095 for `allout-layout'.
1096 C-c C-SPC allout-mark-topic
1097 C-c = c allout-copy-exposed-to-buffer
1098 Duplicate outline, sans concealed text, to
1099 buffer with name derived from derived from
1100 that of current buffer - \"*XXX exposed*\".
1101 C-c = p allout-flatten-exposed-to-buffer
1102 Like above 'copy-exposed', but convert topic
1103 prefixes to section.subsection... numeric
1105 ESC ESC (allout-init t) Setup emacs session for outline mode
1110 Hot-spot operation provides a means for easy, single-keystroke outline
1111 navigation and exposure control.
1114 When the text cursor is positioned directly on the bullet character of
1115 a topic, regular characters (a to z) invoke the commands of the
1116 corresponding allout-mode keymap control chars. For example, \"f\"
1117 would invoke the command typically bound to \"C-c C-f\"
1118 \(\\[allout-forward-current-level] `allout-forward-current-level').
1120 Thus, by positioning the cursor on a topic bullet, you can execute
1121 the outline navigation and manipulation commands with a single
1122 keystroke. Non-literal chars never get this special translation, so
1123 you can use them to get away from the hot-spot, and back to normal
1126 Note that the command `allout-beginning-of-current-entry' \(\\[allout-beginning-of-current-entry]\)
1127 will move to the hot-spot when the cursor is already located at the
1128 beginning of the current entry, so you can simply hit \\[allout-beginning-of-current-entry]
1129 twice in a row to get to the hot-spot.
1133 Topic hierarchy constituents - TOPICS and SUBTOPICS:
1135 TOPIC: A basic, coherent component of an emacs outline. It can
1136 contain other topics, and it can be subsumed by other topics,
1138 The visible topic most immediately containing the cursor.
1139 DEPTH: The degree of nesting of a topic; it increases with
1140 containment. Also called the:
1141 LEVEL: The same as DEPTH.
1144 The topics that contain a topic.
1145 PARENT: A topic's immediate ancestor. It has a depth one less than
1148 The topics contained by a topic;
1150 An immediate offspring of a topic;
1152 The immediate offspring of a topic.
1154 Topics having the same parent and depth.
1156 Topic text constituents:
1158 HEADER: The first line of a topic, include the topic PREFIX and header
1160 PREFIX: The leading text of a topic which which distinguishes it from
1161 normal text. It has a strict form, which consists of a
1162 prefix-lead string, padding, and a bullet. The bullet may be
1163 followed by a number, indicating the ordinal number of the
1164 topic among its siblings, a space, and then the header text.
1166 The relative length of the PREFIX determines the nesting depth
1169 The string at the beginning of a topic prefix, normally a `.'.
1170 It can be customized by changing the setting of
1171 `allout-header-prefix' and then reinitializing `allout-mode'.
1173 By setting the prefix-lead to the comment-string of a
1174 programming language, you can embed outline structuring in
1175 program code without interfering with the language processing
1176 of that code. See `allout-use-mode-specific-leader'
1177 docstring for more detail.
1179 Spaces or asterisks which separate the prefix-lead and the
1180 bullet, according to the depth of the topic.
1181 BULLET: A character at the end of the topic prefix, it must be one of
1182 the characters listed on `allout-plain-bullets-string' or
1183 `allout-distinctive-bullets-string'. (See the documentation
1184 for these variables for more details.) The default choice of
1185 bullet when generating varies in a cycle with the depth of the
1187 ENTRY: The text contained in a topic before any offspring.
1188 BODY: Same as ENTRY.
1192 The state of a topic which determines the on-screen visibility
1193 of its offspring and contained text.
1195 Topics and entry text whose display is inhibited. Contiguous
1196 units of concealed text is represented by `...' ellipses.
1197 (Ref the `selective-display' var.)
1199 Concealed topics are effectively collapsed within an ancestor.
1200 CLOSED: A topic whose immediate offspring and body-text is concealed.
1201 OPEN: A topic that is not closed, though its offspring or body may be."
1205 (let* ((active (and (not (equal major-mode
'outline
))
1207 ; Massage universal-arg `toggle' val:
1209 (or (and (listp toggle
)(car toggle
))
1211 ; Activation specifically demanded?
1212 (explicit-activation (or
1215 (or (symbolp toggle
)
1216 (and (natnump toggle
)
1217 (not (zerop toggle
)))))))
1218 ;; allout-mode already called once during this complex command?
1219 (same-complex-command (eq allout-v18
/19-file-var-hack
1220 (car command-history
)))
1224 ; See comments below re v19.18,.19 bug.
1225 (setq allout-v18
/19-file-var-hack
(car command-history
))
1229 ;; Provision for v19.18, 19.19 bug -
1230 ;; Emacs v 19.18, 19.19 file-var code invokes prop-line-designated
1231 ;; modes twice when file is visited. We have to avoid toggling mode
1232 ;; off on second invocation, so we detect it as best we can, and
1234 ((and same-complex-command
; Still in same complex command
1235 ; as last time `allout-mode' invoked.
1236 active
; Already activated.
1237 (not explicit-activation
) ; Prop-line file-vars don't have args.
1238 (string-match "^19.1[89]" ; Bug only known to be in v19.18 and
1239 emacs-version
)); 19.19.
1243 ((and (not explicit-activation
)
1245 ; Activation not explicitly
1246 ; requested, and either in
1247 ; active state or *de*activation
1248 ; specifically requested:
1249 (setq allout-explicitly-deactivated t
)
1251 (if allout-old-style-prefixes
1253 (allout-resumptions 'allout-primary-bullet
)
1254 (allout-resumptions 'allout-old-style-prefixes
)))
1255 (allout-resumptions 'selective-display
)
1256 (if (and (boundp 'before-change-functions
) before-change-functions
)
1257 (allout-resumptions 'before-change-functions
))
1258 (setq write-contents-functions
1259 (delq 'allout-write-file-hook
1260 write-contents-functions
))
1261 (allout-resumptions 'paragraph-start
)
1262 (allout-resumptions 'paragraph-separate
)
1263 (allout-resumptions (if (string-match "^18" emacs-version
)
1265 'auto-fill-function
))
1266 (allout-resumptions 'allout-former-auto-filler
)
1267 (setq allout-mode nil
))
1271 (setq allout-explicitly-deactivated nil
)
1272 (if allout-old-style-prefixes
1273 (progn ; Inhibit all the fancy formatting:
1274 (allout-resumptions 'allout-primary-bullet
'("*"))
1275 (allout-resumptions 'allout-old-style-prefixes
'(()))))
1277 (allout-infer-header-lead)
1278 (allout-infer-body-reindent)
1282 ; Produce map from current version
1283 ; of allout-keybindings-list:
1284 (if (boundp 'minor-mode-map-alist
)
1286 (progn ; V19, and maybe lucid and
1287 ; epoch, minor-mode key bindings:
1288 (setq allout-mode-map
1289 (produce-allout-mode-map allout-keybindings-list
))
1290 (produce-allout-mode-menubar-entries)
1291 (fset 'allout-mode-map allout-mode-map
)
1292 ; Include on minor-mode-map-alist,
1293 ; if not already there:
1294 (if (not (member '(allout-mode . allout-mode-map
)
1295 minor-mode-map-alist
))
1296 (setq minor-mode-map-alist
1297 (cons '(allout-mode . allout-mode-map
)
1298 minor-mode-map-alist
))))
1301 (use-local-map (produce-allout-mode-map allout-keybindings-list
1302 (current-local-map)))
1305 ; selective-display is the
1306 ; emacs conditional exposure
1308 (allout-resumptions 'selective-display
'(t))
1309 (if allout-inhibit-protection
1311 (allout-resumptions 'before-change-functions
1312 '(allout-before-change-protect)))
1313 (add-hook 'pre-command-hook
'allout-pre-command-business
)
1314 (add-hook 'post-command-hook
'allout-post-command-business
)
1315 ; Temporarily set by any outline
1316 ; functions that can be trusted to
1317 ; deal properly with concealed text.
1318 (add-hook 'write-contents-functions
'allout-write-file-hook
)
1319 ; Custom auto-fill func, to support
1320 ; respect for topic headline,
1321 ; hanging-indents, etc:
1322 (let* ((fill-func-var (if (string-match "^18" emacs-version
)
1324 'auto-fill-function
))
1325 (fill-func (symbol-value fill-func-var
)))
1326 ;; Register prevailing fill func for use by allout-auto-fill:
1327 (allout-resumptions 'allout-former-auto-filler
(list fill-func
))
1328 ;; Register allout-auto-fill to be used if filling is active:
1329 (allout-resumptions fill-func-var
'(allout-auto-fill)))
1330 ;; Paragraphs are broken by topic headlines.
1331 (make-local-variable 'paragraph-start
)
1332 (allout-resumptions 'paragraph-start
1333 (list (concat paragraph-start
"\\|^\\("
1334 allout-regexp
"\\)")))
1335 (make-local-variable 'paragraph-separate
)
1336 (allout-resumptions 'paragraph-separate
1337 (list (concat paragraph-separate
"\\|^\\("
1338 allout-regexp
"\\)")))
1340 (or (assq 'allout-mode minor-mode-alist
)
1341 (setq minor-mode-alist
1342 (cons '(allout-mode " Allout") minor-mode-alist
)))
1344 (allout-setup-menubar)
1349 (if (and allout-isearch-dynamic-expose
1350 (not (fboundp 'allout-real-isearch-abort
)))
1351 (allout-enwrap-isearch))
1353 (run-hooks 'allout-mode-hook
)
1354 (setq allout-mode t
))
1358 (allout-infer-body-reindent))
1362 allout-auto-activation
1363 (listp allout-layout
)
1364 (and (not (eq allout-auto-activation
'activate
))
1365 (if (eq allout-auto-activation
'ask
)
1366 (if (y-or-n-p (format "Expose %s with layout '%s'? "
1370 (message "Skipped %s layout." (buffer-name))
1374 (message "Adjusting '%s' exposure..." (buffer-name))
1376 (allout-this-or-next-heading)
1379 (apply 'allout-expose-topic
(list allout-layout
))
1380 (message "Adjusting '%s' exposure... done." (buffer-name)))
1381 ;; Problem applying exposure - notify user, but don't
1382 ;; interrupt, eg, file visit:
1383 (error (message "%s" (car (cdr err
)))
1388 ;;;_ > allout-minor-mode
1389 ;;; XXX released verion doesn't do this?
1390 (defalias 'allout-minor-mode
'allout-mode
)
1392 ;;;_ #3 Internal Position State-Tracking - "allout-recent-*" funcs
1393 ;;; All the basic outline functions that directly do string matches to
1394 ;;; evaluate heading prefix location set the variables
1395 ;;; `allout-recent-prefix-beginning' and `allout-recent-prefix-end'
1396 ;;; when successful. Functions starting with `allout-recent-' all
1397 ;;; use this state, providing the means to avoid redundant searches
1398 ;;; for just-established data. This optimization can provide
1399 ;;; significant speed improvement, but it must be employed carefully.
1400 ;;;_ = allout-recent-prefix-beginning
1401 (defvar allout-recent-prefix-beginning
0
1402 "Buffer point of the start of the last topic prefix encountered.")
1403 (make-variable-buffer-local 'allout-recent-prefix-beginning
)
1404 ;;;_ = allout-recent-prefix-end
1405 (defvar allout-recent-prefix-end
0
1406 "Buffer point of the end of the last topic prefix encountered.")
1407 (make-variable-buffer-local 'allout-recent-prefix-end
)
1408 ;;;_ = allout-recent-end-of-subtree
1409 (defvar allout-recent-end-of-subtree
0
1410 "Buffer point last returned by `allout-end-of-current-subtree'.")
1411 (make-variable-buffer-local 'allout-recent-end-of-subtree
)
1412 ;;;_ > allout-prefix-data (beg end)
1413 (defmacro allout-prefix-data
(beg end
)
1414 "Register allout-prefix state data - BEGINNING and END of prefix.
1416 For reference by `allout-recent' funcs. Returns BEGINNING."
1417 `(setq allout-recent-prefix-end
,end
1418 allout-recent-prefix-beginning
,beg
))
1419 ;;;_ > allout-recent-depth ()
1420 (defmacro allout-recent-depth
()
1421 "Return depth of last heading encountered by an outline maneuvering function.
1423 All outline functions which directly do string matches to assess
1424 headings set the variables `allout-recent-prefix-beginning' and
1425 `allout-recent-prefix-end' if successful. This function uses those settings
1426 to return the current depth."
1428 '(max 1 (- allout-recent-prefix-end
1429 allout-recent-prefix-beginning
1430 allout-header-subtraction
)))
1431 ;;;_ > allout-recent-prefix ()
1432 (defmacro allout-recent-prefix
()
1433 "Like `allout-recent-depth', but returns text of last encountered prefix.
1435 All outline functions which directly do string matches to assess
1436 headings set the variables `allout-recent-prefix-beginning' and
1437 `allout-recent-prefix-end' if successful. This function uses those settings
1438 to return the current depth."
1439 '(buffer-substring allout-recent-prefix-beginning
1440 allout-recent-prefix-end
))
1441 ;;;_ > allout-recent-bullet ()
1442 (defmacro allout-recent-bullet
()
1443 "Like allout-recent-prefix, but returns bullet of last encountered prefix.
1445 All outline functions which directly do string matches to assess
1446 headings set the variables `allout-recent-prefix-beginning' and
1447 `allout-recent-prefix-end' if successful. This function uses those settings
1448 to return the current depth of the most recently matched topic."
1449 '(buffer-substring (1- allout-recent-prefix-end
)
1450 allout-recent-prefix-end
))
1454 ;;;_ - Position Assessment
1455 ;;;_ : Location Predicates
1456 ;;;_ > allout-on-current-heading-p ()
1457 (defun allout-on-current-heading-p ()
1458 "Return non-nil if point is on current visible topics' header line.
1460 Actually, returns prefix beginning point."
1463 (and (looking-at allout-regexp
)
1464 (allout-prefix-data (match-beginning 0) (match-end 0)))))
1465 ;;;_ > allout-on-heading-p ()
1466 (defalias 'allout-on-heading-p
'allout-on-current-heading-p
)
1467 ;;;_ > allout-e-o-prefix-p ()
1468 (defun allout-e-o-prefix-p ()
1469 "True if point is located where current topic prefix ends, heading begins."
1470 (and (save-excursion (beginning-of-line)
1471 (looking-at allout-regexp
))
1472 (= (point)(save-excursion (allout-end-of-prefix)(point)))))
1473 ;;;_ > allout-hidden-p ()
1474 (defmacro allout-hidden-p
()
1475 "True if point is in hidden text."
1477 (and (re-search-backward "[\n\r]" () t
)
1478 (= ?
\r (following-char)))))
1479 ;;;_ > allout-visible-p ()
1480 (defmacro allout-visible-p
()
1481 "True if point is not in hidden text."
1483 '(not (allout-hidden-p)))
1484 ;;;_ : Location attributes
1485 ;;;_ > allout-depth ()
1486 (defsubst allout-depth
()
1487 "Like `allout-current-depth', but respects hidden as well as visible topics."
1489 (if (allout-goto-prefix)
1490 (allout-recent-depth)
1492 ;; Oops, no prefix, zero prefix data:
1493 (allout-prefix-data (point)(point))
1494 ;; ... and return 0:
1496 ;;;_ > allout-current-depth ()
1497 (defmacro allout-current-depth
()
1498 "Return nesting depth of visible topic most immediately containing point."
1500 (if (allout-back-to-current-heading)
1502 (- allout-recent-prefix-end
1503 allout-recent-prefix-beginning
1504 allout-header-subtraction
))
1506 ;;;_ > allout-get-current-prefix ()
1507 (defun allout-get-current-prefix ()
1508 "Topic prefix of the current topic."
1510 (if (allout-goto-prefix)
1511 (allout-recent-prefix))))
1512 ;;;_ > allout-get-bullet ()
1513 (defun allout-get-bullet ()
1514 "Return bullet of containing topic (visible or not)."
1516 (and (allout-goto-prefix)
1517 (allout-recent-bullet))))
1518 ;;;_ > allout-current-bullet ()
1519 (defun allout-current-bullet ()
1520 "Return bullet of current (visible) topic heading, or none if none found."
1523 (allout-back-to-current-heading)
1524 (buffer-substring (- allout-recent-prefix-end
1)
1525 allout-recent-prefix-end
))
1526 ;; Quick and dirty provision, ostensibly for missing bullet:
1527 ('args-out-of-range nil
))
1529 ;;;_ > allout-get-prefix-bullet (prefix)
1530 (defun allout-get-prefix-bullet (prefix)
1531 "Return the bullet of the header prefix string PREFIX."
1532 ;; Doesn't make sense if we're old-style prefixes, but this just
1533 ;; oughtn't be called then, so forget about it...
1534 (if (string-match allout-regexp prefix
)
1535 (substring prefix
(1- (match-end 0)) (match-end 0))))
1536 ;;;_ > allout-sibling-index (&optional depth)
1537 (defun allout-sibling-index (&optional depth
)
1538 "Item number of this prospective topic among its siblings.
1540 If optional arg depth is greater than current depth, then we're
1541 opening a new level, and return 0.
1543 If less than this depth, ascend to that depth and count..."
1546 (cond ((and depth
(<= depth
0) 0))
1547 ((or (not depth
) (= depth
(allout-depth)))
1549 (while (allout-previous-sibling (allout-recent-depth) nil
)
1550 (setq index
(1+ index
)))
1552 ((< depth
(allout-recent-depth))
1553 (allout-ascend-to-depth depth
)
1554 (allout-sibling-index))
1556 ;;;_ > allout-topic-flat-index ()
1557 (defun allout-topic-flat-index ()
1558 "Return a list indicating point's numeric section.subsect.subsubsect...
1559 Outermost is first."
1560 (let* ((depth (allout-depth))
1561 (next-index (allout-sibling-index depth
))
1563 (while (> next-index
0)
1564 (setq rev-sibls
(cons next-index rev-sibls
))
1565 (setq depth
(1- depth
))
1566 (setq next-index
(allout-sibling-index depth
)))
1570 ;;;_ - Navigation macros
1571 ;;;_ > allout-next-heading ()
1572 (defsubst allout-next-heading
()
1573 "Move to the heading for the topic \(possibly invisible) before this one.
1575 Returns the location of the heading, or nil if none found."
1577 (if (and (bobp) (not (eobp)))
1580 (if (re-search-forward allout-line-boundary-regexp nil
0)
1581 (allout-prefix-data ; Got valid location state - set vars:
1582 (goto-char (or (match-beginning 2)
1583 allout-recent-prefix-beginning
))
1584 (or (match-end 2) allout-recent-prefix-end
))))
1585 ;;;_ : allout-this-or-next-heading
1586 (defun allout-this-or-next-heading ()
1587 "Position cursor on current or next heading."
1588 ;; A throwaway non-macro that is defined after allout-next-heading
1589 ;; and usable by allout-mode.
1590 (if (not (allout-goto-prefix)) (allout-next-heading)))
1591 ;;;_ > allout-previous-heading ()
1592 (defmacro allout-previous-heading
()
1593 "Move to the prior \(possibly invisible) heading line.
1595 Return the location of the beginning of the heading, or nil if not found."
1599 (allout-goto-prefix)
1601 ;; searches are unbounded and return nil if failed:
1602 (or (re-search-backward allout-line-boundary-regexp nil
0)
1603 (looking-at allout-bob-regexp
))
1604 (progn ; Got valid location state - set vars:
1606 (goto-char (or (match-beginning 2)
1607 allout-recent-prefix-beginning
))
1608 (or (match-end 2) allout-recent-prefix-end
))))))
1610 ;;;_ - Subtree Charting
1611 ;;;_ " These routines either produce or assess charts, which are
1612 ;;; nested lists of the locations of topics within a subtree.
1614 ;;; Use of charts enables efficient navigation of subtrees, by
1615 ;;; requiring only a single regexp-search based traversal, to scope
1616 ;;; out the subtopic locations. The chart then serves as the basis
1617 ;;; for assessment or adjustment of the subtree, without redundant
1618 ;;; traversal of the structure.
1620 ;;;_ > allout-chart-subtree (&optional levels orig-depth prev-depth)
1621 (defun allout-chart-subtree (&optional levels orig-depth prev-depth
)
1622 "Produce a location \"chart\" of subtopics of the containing topic.
1624 Optional argument LEVELS specifies the depth \(relative to start
1625 depth) for the chart. Subsequent optional args are not for public
1628 Charts are used to capture outline structure, so that outline altering
1629 routines need assess the structure only once, and then use the chart
1630 for their elaborate manipulations.
1632 Topics are entered in the chart so the last one is at the car.
1633 The entry for each topic consists of an integer indicating the point
1634 at the beginning of the topic. Charts for offspring consists of a
1635 list containing, recursively, the charts for the respective subtopics.
1636 The chart for a topics' offspring precedes the entry for the topic
1639 The other function parameters are for internal recursion, and should
1640 not be specified by external callers. ORIG-DEPTH is depth of topic at
1641 starting point, and PREV-DEPTH is depth of prior topic."
1643 (let ((original (not orig-depth
)) ; `orig-depth' set only in recursion.
1646 (if original
; Just starting?
1647 ; Register initial settings and
1648 ; position to first offspring:
1649 (progn (setq orig-depth
(allout-depth))
1650 (or prev-depth
(setq prev-depth
(1+ orig-depth
)))
1651 (allout-next-heading)))
1653 ;; Loop over the current levels' siblings. Besides being more
1654 ;; efficient than tail-recursing over a level, it avoids exceeding
1655 ;; the typically quite constrained emacs max-lisp-eval-depth.
1657 ;; Probably would speed things up to implement loop-based stack
1658 ;; operation rather than recursing for lower levels. Bah.
1660 (while (and (not (eobp))
1661 ; Still within original topic?
1662 (< orig-depth
(setq curr-depth
(allout-recent-depth)))
1663 (cond ((= prev-depth curr-depth
)
1664 ;; Register this one and move on:
1665 (setq chart
(cons (point) chart
))
1666 (if (and levels
(<= levels
1))
1667 ;; At depth limit - skip sublevels:
1668 (or (allout-next-sibling curr-depth
)
1669 ;; or no more siblings - proceed to
1670 ;; next heading at lesser depth:
1671 (while (and (<= curr-depth
1672 (allout-recent-depth))
1673 (allout-next-heading))))
1674 (allout-next-heading)))
1676 ((and (< prev-depth curr-depth
)
1679 ;; Recurse on deeper level of curr topic:
1681 (cons (allout-chart-subtree (and levels
1686 ;; ... then continue with this one.
1689 ;; ... else nil if we've ascended back to prev-depth.
1693 (if original
; We're at the last sibling on
1694 ; the original level. Position
1696 (progn (and (not (eobp)) (forward-char -
1))
1697 (and (memq (preceding-char) '(?
\n ?
\r))
1698 (memq (aref (buffer-substring (max 1 (- (point) 3))
1703 (setq allout-recent-end-of-subtree
(point))))
1705 chart
; (nreverse chart) not necessary,
1706 ; and maybe not preferable.
1708 ;;;_ > allout-chart-siblings (&optional start end)
1709 (defun allout-chart-siblings (&optional start end
)
1710 "Produce a list of locations of this and succeeding sibling topics.
1711 Effectively a top-level chart of siblings. See `allout-chart-subtree'
1712 for an explanation of charts."
1714 (if (allout-goto-prefix)
1715 (let ((chart (list (point))))
1716 (while (allout-next-sibling)
1717 (setq chart
(cons (point) chart
)))
1718 (if chart
(setq chart
(nreverse chart
)))))))
1719 ;;;_ > allout-chart-to-reveal (chart depth)
1720 (defun allout-chart-to-reveal (chart depth
)
1722 "Return a flat list of hidden points in subtree CHART, up to DEPTH.
1724 Note that point can be left at any of the points on chart, or at the
1728 (while (and (or (eq depth t
) (> depth
0))
1730 (setq here
(car chart
))
1732 (let ((further (allout-chart-to-reveal here
(or (eq depth t
)
1734 ;; We're on the start of a subtree - recurse with it, if there's
1735 ;; more depth to go:
1736 (if further
(setq result
(append further result
)))
1737 (setq chart
(cdr chart
)))
1739 (if (= (preceding-char) ?
\r)
1740 (setq result
(cons here result
)))
1741 (setq chart
(cdr chart
))))
1743 ;;;_ X allout-chart-spec (chart spec &optional exposing)
1744 (defun allout-chart-spec (chart spec
&optional exposing
)
1745 "Not yet \(if ever) implemented.
1747 Produce exposure directives given topic/subtree CHART and an exposure SPEC.
1749 Exposure spec indicates the locations to be exposed and the prescribed
1750 exposure status. Optional arg EXPOSING is an integer, with 0
1751 indicating pending concealment, anything higher indicating depth to
1752 which subtopic headers should be exposed, and negative numbers
1753 indicating (negative of) the depth to which subtopic headers and
1754 bodies should be exposed.
1756 The produced list can have two types of entries. Bare numbers
1757 indicate points in the buffer where topic headers that should be
1760 - bare negative numbers indicates that the topic starting at the
1761 point which is the negative of the number should be opened,
1762 including their entries.
1763 - bare positive values indicate that this topic header should be
1765 - Lists signify the beginning and end points of regions that should
1766 be flagged, and the flag to employ. (For concealment: `\(\?r\)', and
1772 (setq spec
(cdr spec
)))
1776 ;;;_ > allout-goto-prefix ()
1777 (defun allout-goto-prefix ()
1778 "Put point at beginning of immediately containing outline topic.
1780 Goes to most immediate subsequent topic if none immediately containing.
1782 Not sensitive to topic visibility.
1784 Returns the point at the beginning of the prefix, or nil if none."
1787 (while (and (not done
)
1788 (re-search-backward "[\n\r]" nil
1))
1790 (if (looking-at allout-regexp
)
1791 (setq done
(allout-prefix-data (match-beginning 0)
1795 (cond ((looking-at allout-regexp
)
1796 (allout-prefix-data (match-beginning 0)(match-end 0)))
1797 ((allout-next-heading))
1800 ;;;_ > allout-end-of-prefix ()
1801 (defun allout-end-of-prefix (&optional ignore-decorations
)
1802 "Position cursor at beginning of header text.
1804 If optional IGNORE-DECORATIONS is non-nil, put just after bullet,
1805 otherwise skip white space between bullet and ensuing text."
1807 (if (not (allout-goto-prefix))
1809 (let ((match-data (match-data)))
1810 (goto-char (match-end 0))
1811 (if ignore-decorations
1813 (while (looking-at "[0-9]") (forward-char 1))
1814 (if (and (not (eolp)) (looking-at "\\s-")) (forward-char 1)))
1815 (store-match-data match-data
))
1816 ;; Reestablish where we are:
1817 (allout-current-depth)))
1818 ;;;_ > allout-current-bullet-pos ()
1819 (defun allout-current-bullet-pos ()
1820 "Return position of current \(visible) topic's bullet."
1822 (if (not (allout-current-depth))
1824 (1- (match-end 0))))
1825 ;;;_ > allout-back-to-current-heading ()
1826 (defun allout-back-to-current-heading ()
1827 "Move to heading line of current topic, or beginning if already on the line."
1830 (prog1 (or (allout-on-current-heading-p)
1831 (and (re-search-backward (concat "^\\(" allout-regexp
"\\)")
1834 (allout-prefix-data (match-beginning 1)(match-end 1))))
1835 (if (interactive-p) (allout-end-of-prefix))))
1836 ;;;_ > allout-back-to-heading ()
1837 (defalias 'allout-back-to-heading
'allout-back-to-current-heading
)
1838 ;;;_ > allout-pre-next-preface ()
1839 (defun allout-pre-next-preface ()
1840 "Skip forward to just before the next heading line.
1842 Returns that character position."
1844 (if (re-search-forward allout-line-boundary-regexp nil
'move
)
1845 (prog1 (goto-char (match-beginning 0))
1846 (allout-prefix-data (match-beginning 2)(match-end 2)))))
1847 ;;;_ > allout-end-of-current-subtree ()
1848 (defun allout-end-of-current-subtree ()
1849 "Put point at the end of the last leaf in the currently visible topic."
1851 (allout-back-to-current-heading)
1852 (let ((level (allout-recent-depth)))
1853 (allout-next-heading)
1854 (while (and (not (eobp))
1855 (> (allout-recent-depth) level
))
1856 (allout-next-heading))
1857 (and (not (eobp)) (forward-char -
1))
1858 (and (memq (preceding-char) '(?
\n ?
\r))
1859 (memq (aref (buffer-substring (max 1 (- (point) 3)) (point)) 1)
1862 (setq allout-recent-end-of-subtree
(point))))
1863 ;;;_ > allout-beginning-of-current-entry ()
1864 (defun allout-beginning-of-current-entry ()
1865 "When not already there, position point at beginning of current topic's body.
1867 If already there, move cursor to bullet for hot-spot operation.
1868 \(See `allout-mode' doc string for details on hot-spot operation.)"
1870 (let ((start-point (point)))
1871 (allout-end-of-prefix)
1872 (if (and (interactive-p)
1873 (= (point) start-point
))
1874 (goto-char (allout-current-bullet-pos)))))
1875 ;;;_ > allout-end-of-current-entry ()
1876 (defun allout-end-of-current-entry ()
1877 "Position the point at the end of the current topics' entry."
1880 (prog1 (allout-pre-next-preface)
1881 (if (and (not (bobp))(looking-at "^$"))
1882 (forward-char -
1))))
1883 ;;;_ > allout-end-of-current-heading ()
1884 (defun allout-end-of-current-heading ()
1886 (allout-beginning-of-current-entry)
1889 (defalias 'allout-end-of-heading
'allout-end-of-current-heading
)
1892 ;;;_ > allout-ascend-to-depth (depth)
1893 (defun allout-ascend-to-depth (depth)
1894 "Ascend to depth DEPTH, returning depth if successful, nil if not."
1895 (if (and (> depth
0)(<= depth
(allout-depth)))
1896 (let ((last-good (point)))
1897 (while (and (< depth
(allout-depth))
1898 (setq last-good
(point))
1899 (allout-beginning-of-level)
1900 (allout-previous-heading)))
1901 (if (= (allout-recent-depth) depth
)
1902 (progn (goto-char allout-recent-prefix-beginning
)
1904 (goto-char last-good
)
1906 (if (interactive-p) (allout-end-of-prefix))))
1907 ;;;_ > allout-ascend ()
1908 (defun allout-ascend ()
1909 "Ascend one level, returning t if successful, nil if not."
1911 (if (allout-beginning-of-level)
1912 (allout-previous-heading))
1913 (if (interactive-p) (allout-end-of-prefix))))
1914 ;;;_ > allout-descend-to-depth (depth)
1915 (defun allout-descend-to-depth (depth)
1916 "Descend to depth DEPTH within current topic.
1918 Returning depth if successful, nil if not."
1919 (let ((start-point (point))
1920 (start-depth (allout-depth)))
1922 (and (> (allout-depth) 0)
1923 (not (= depth
(allout-recent-depth))) ; ... not there yet
1924 (allout-next-heading) ; ... go further
1925 (< start-depth
(allout-recent-depth)))) ; ... still in topic
1926 (if (and (> (allout-depth) 0)
1927 (= (allout-recent-depth) depth
))
1929 (goto-char start-point
)
1932 ;;;_ > allout-up-current-level (arg &optional dont-complain)
1933 (defun allout-up-current-level (arg &optional dont-complain
)
1934 "Move out ARG levels from current visible topic.
1936 Positions on heading line of containing topic. Error if unable to
1937 ascend that far, or nil if unable to ascend but optional arg
1938 DONT-COMPLAIN is non-nil."
1940 (allout-back-to-current-heading)
1941 (let ((present-level (allout-recent-depth))
1945 ;; Loop for iterating arg:
1946 (while (and (> (allout-recent-depth) 1)
1950 (setq last-good
(point))
1951 ;; Loop for going back over current or greater depth:
1952 (while (and (not (< (allout-recent-depth) present-level
))
1953 (or (allout-previous-visible-heading 1)
1954 (not (setq failed present-level
)))))
1955 (setq present-level
(allout-current-depth))
1956 (setq arg
(- arg
1)))
1959 (progn (goto-char last-good
)
1960 (if (interactive-p) (allout-end-of-prefix))
1961 (if (not dont-complain
)
1962 (error "Can't ascend past outermost level")
1963 (if (interactive-p) (allout-end-of-prefix))
1965 (if (interactive-p) (allout-end-of-prefix))
1966 allout-recent-prefix-beginning
)))
1969 ;;;_ > allout-next-sibling (&optional depth backward)
1970 (defun allout-next-sibling (&optional depth backward
)
1971 "Like `allout-forward-current-level', but respects invisible topics.
1973 Traverse at optional DEPTH, or current depth if none specified.
1975 Go backward if optional arg BACKWARD is non-nil.
1977 Return depth if successful, nil otherwise."
1979 (if (and backward
(bobp))
1981 (let ((start-depth (or depth
(allout-depth)))
1982 (start-point (point))
1984 (while (and (not (if backward
(bobp) (eobp)))
1985 (if backward
(allout-previous-heading)
1986 (allout-next-heading))
1987 (> (setq last-depth
(allout-recent-depth)) start-depth
)))
1988 (if (and (not (eobp))
1989 (and (> (or last-depth
(allout-depth)) 0)
1990 (= (allout-recent-depth) start-depth
)))
1991 allout-recent-prefix-beginning
1992 (goto-char start-point
)
1993 (if depth
(allout-depth) start-depth
)
1995 ;;;_ > allout-previous-sibling (&optional depth backward)
1996 (defun allout-previous-sibling (&optional depth backward
)
1997 "Like `allout-forward-current-level', but backwards & respect invisible topics.
1999 Optional DEPTH specifies depth to traverse, default current depth.
2001 Optional BACKWARD reverses direction.
2003 Return depth if successful, nil otherwise."
2004 (allout-next-sibling depth
(not backward
))
2006 ;;;_ > allout-snug-back ()
2007 (defun allout-snug-back ()
2008 "Position cursor at end of previous topic
2010 Presumes point is at the start of a topic prefix."
2011 (if (or (bobp) (eobp))
2014 (if (or (bobp) (not (memq (preceding-char) '(?
\n ?
\r))))
2017 (if (or (bobp) (not (memq (preceding-char) '(?
\n ?
\r))))
2020 ;;;_ > allout-beginning-of-level ()
2021 (defun allout-beginning-of-level ()
2022 "Go back to the first sibling at this level, visible or not."
2023 (allout-end-of-level 'backward
))
2024 ;;;_ > allout-end-of-level (&optional backward)
2025 (defun allout-end-of-level (&optional backward
)
2026 "Go to the last sibling at this level, visible or not."
2028 (let ((depth (allout-depth)))
2029 (while (allout-previous-sibling depth nil
))
2030 (prog1 (allout-recent-depth)
2031 (if (interactive-p) (allout-end-of-prefix)))))
2032 ;;;_ > allout-next-visible-heading (arg)
2033 (defun allout-next-visible-heading (arg)
2034 "Move to the next ARG'th visible heading line, backward if arg is negative.
2036 Move as far as possible in indicated direction \(beginning or end of
2037 buffer) if headings are exhausted."
2040 (let* ((backward (if (< arg
0) (setq arg
(* -
1 arg
))))
2041 (step (if backward -
1 1))
2042 (start-point (point))
2045 (while (> arg
0) ; limit condition
2046 (while (and (not (if backward
(bobp)(eobp))) ; boundary condition
2047 ;; Move, skipping over all those concealed lines:
2048 (< -
1 (forward-line step
))
2049 (not (setq got
(looking-at allout-regexp
)))))
2050 ;; Register this got, it may be the last:
2051 (if got
(setq prev got
))
2052 (setq arg
(1- arg
)))
2053 (cond (got ; Last move was to a prefix:
2054 (allout-prefix-data (match-beginning 0) (match-end 0))
2055 (allout-end-of-prefix))
2056 (prev ; Last move wasn't, but prev was:
2057 (allout-prefix-data (match-beginning 0) (match-end 0)))
2058 ((not backward
) (end-of-line) nil
))))
2059 ;;;_ > allout-previous-visible-heading (arg)
2060 (defun allout-previous-visible-heading (arg)
2061 "Move to the previous heading line.
2063 With argument, repeats or can move forward if negative.
2064 A heading line is one that starts with a `*' (or that `allout-regexp'
2067 (allout-next-visible-heading (- arg
)))
2068 ;;;_ > allout-forward-current-level (arg)
2069 (defun allout-forward-current-level (arg)
2070 "Position point at the next heading of the same level.
2072 Takes optional repeat-count, goes backward if count is negative.
2074 Returns resulting position, else nil if none found."
2076 (let ((start-depth (allout-current-depth))
2077 (start-point (point))
2079 (backward (> 0 arg
))
2083 (if (= 0 start-depth
)
2084 (error "No siblings, not in a topic..."))
2085 (if backward
(setq arg
(* -
1 arg
)))
2086 (while (not (or (zerop arg
)
2088 (while (and (not (if backward
(bobp) (eobp)))
2089 (if backward
(allout-previous-visible-heading 1)
2090 (allout-next-visible-heading 1))
2091 (> (setq last-depth
(allout-recent-depth)) start-depth
)))
2092 (if (and last-depth
(= last-depth start-depth
)
2093 (not (if backward
(bobp) (eobp))))
2094 (setq last-good
(point)
2096 (setq at-boundary t
)))
2097 (if (and (not (eobp))
2099 (and (> (or last-depth
(allout-depth)) 0)
2100 (= (allout-recent-depth) start-depth
)))
2101 allout-recent-prefix-beginning
2102 (goto-char last-good
)
2103 (if (not (interactive-p))
2105 (allout-end-of-prefix)
2106 (error "Hit %s level %d topic, traversed %d of %d requested"
2107 (if backward
"first" "last")
2108 (allout-recent-depth)
2109 (- (abs start-arg
) arg
)
2110 (abs start-arg
))))))
2111 ;;;_ > allout-backward-current-level (arg)
2112 (defun allout-backward-current-level (arg)
2113 "Inverse of `allout-forward-current-level'."
2116 (let ((current-prefix-arg (* -
1 arg
)))
2117 (call-interactively 'allout-forward-current-level
))
2118 (allout-forward-current-level (* -
1 arg
))))
2123 ;;;_ > allout-before-change-protect (beg end)
2124 (defun allout-before-change-protect (beg end
)
2125 "Outline before-change hook, regulates changes to concealed text.
2127 Reveal concealed text that would be changed by current command, and
2128 offer user choice to commit or forego the change. Unchanged text is
2129 reconcealed. User has option to have changed text reconcealed.
2131 Undo commands are specially treated - the user is not prompted for
2132 choice, the undoes are always committed (based on presumption that the
2133 things being undone were already subject to this regulation routine),
2134 and undoes always leave the changed stuff exposed.
2136 Changes to concealed regions are ignored while file is being written.
2137 \(This is for the sake of functions that do change the file during
2138 writes, like crypt and zip modes.)
2140 Locally bound in outline buffers to `before-change-functions', which
2141 in emacs 19 is run before any change to the buffer.
2143 Any functions which set [`this-command' to `undo', or which set]
2144 `allout-override-protect' non-nil (as does, eg, allout-flag-chars)
2145 are exempt from this restriction."
2146 (if (and (allout-mode-p)
2147 ; allout-override-protect
2148 ; set by functions that know what
2149 ; they're doing, eg outline internals:
2150 (not allout-override-protect
)
2151 (not allout-during-write-cue
)
2152 (save-match-data ; Preserve operation position state.
2153 ; Both beginning and end chars must
2155 (save-excursion (if (memq this-command
'(newline open-line
))
2156 ;; Compensate for stupid emacs {new,
2157 ;; open-}line display optimization:
2161 (or (allout-hidden-p)
2162 (and (not (= beg end
))
2164 (allout-hidden-p))))))
2166 (if (equal this-command
'undo
)
2167 ;; Allow undo without inhibition.
2168 ;; - Undoing new and open-line hits stupid emacs redisplay
2169 ;; optimization (em 19 cmds.c, ~ line 200).
2170 ;; - Presumably, undoing what was properly protected when
2172 ;; - Undo may be users' only recourse in protection faults.
2173 ;; So, expose what getting changed:
2174 (progn (message "Undo! - exposing concealed target...")
2175 (if (allout-hidden-p)
2176 (allout-show-children))
2179 (rehide-completely (save-excursion (allout-goto-prefix)
2184 (if (condition-case err
2185 ;; Condition case to catch keyboard quits during reads.
2187 ; Give them a peek where
2189 (if (eolp) (setq rehide-place
2190 (allout-goto-prefix)))
2191 (allout-show-entry))
2192 ; Present the message, but...
2193 ; leave the cursor at the location
2194 ; until they respond:
2195 ; Then interpret the response:
2198 (message (concat "Change inside concealed"
2200 "(n or 'y'/'r'eclose)"))
2201 (setq response
(read-char))
2203 (cond ((memq response
'(?r ?R
))
2204 (setq response
'reclose
))
2205 ((memq response
'(?y ?Y ?
))
2207 ((memq response
'(?n ?N
127))
2212 "`r' means `yes, then reclose'")
2214 (t (message "Please answer y, n, or r")
2220 (if (eq response
'reclose
)
2222 (if rehide-place
(goto-char rehide-place
))
2223 (if rehide-completely
2224 (allout-hide-current-entry-completely)
2225 (allout-hide-current-entry)))
2226 (if (allout-ascend-to-depth (1- (allout-recent-depth)))
2227 (allout-show-children)
2228 (allout-show-to-offshoot)))
2230 (if rehide-completely
2232 (if rehide-place
(goto-char rehide-place
))
2233 (allout-hide-current-entry-completely))
2234 (allout-hide-current-entry))
2236 "Change within concealed region prevented.")))))))
2239 ;;;_ = allout-post-goto-bullet
2240 (defvar allout-post-goto-bullet nil
2241 "Outline internal var, for `allout-pre-command-business' hot-spot operation.
2243 When set, tells post-processing to reposition on topic bullet, and
2244 then unset it. Set by `allout-pre-command-business' when implementing
2245 hot-spot operation, where literal characters typed over a topic bullet
2246 are mapped to the command of the corresponding control-key on the
2247 `allout-mode-map'.")
2248 (make-variable-buffer-local 'allout-post-goto-bullet
)
2249 ;;;_ > allout-post-command-business ()
2250 (defun allout-post-command-business ()
2251 "Outline `post-command-hook' function.
2253 - Null `allout-override-protect', so it's not left open.
2255 - Implement (and clear) `allout-post-goto-bullet', for hot-spot
2258 - Massages buffer-undo-list so successive, standard character self-inserts are
2259 aggregated. This kludge compensates for lack of undo bunching when
2260 `before-change-functions' is used."
2262 ; Apply any external change func:
2263 (if (not (allout-mode-p)) ; In allout-mode.
2265 (setq allout-override-protect nil
)
2266 (if allout-isearch-dynamic-expose
2267 (allout-isearch-rectification))
2268 (if allout-during-write-cue
2269 ;; Was used by allout-before-change-protect, done with it now:
2270 (setq allout-during-write-cue nil
))
2271 ;; Undo bunching business:
2272 (if (and (listp buffer-undo-list
) ; Undo history being kept.
2273 (equal this-command
'self-insert-command
)
2274 (equal last-command
'self-insert-command
))
2275 (let* ((prev-stuff (cdr buffer-undo-list
))
2276 (before-prev-stuff (cdr (cdr prev-stuff
)))
2277 cur-cell cur-from cur-to
2278 prev-cell prev-from prev-to
)
2279 (if (and before-prev-stuff
; Goes back far enough to bother,
2280 (not (car prev-stuff
)) ; and break before current,
2281 (not (car before-prev-stuff
)) ; !and break before prev!
2282 (setq prev-cell
(car (cdr prev-stuff
))) ; contents now,
2283 (setq cur-cell
(car buffer-undo-list
)) ; contents prev.
2285 ;; cur contents denote a single char insertion:
2286 (numberp (setq cur-from
(car cur-cell
)))
2287 (numberp (setq cur-to
(cdr cur-cell
)))
2288 (= 1 (- cur-to cur-from
))
2290 ;; prev contents denote fewer than aggregate-limit
2292 (numberp (setq prev-from
(car prev-cell
)))
2293 (numberp (setq prev-to
(cdr prev-cell
)))
2295 (> allout-undo-aggregation
(- prev-to prev-from
)))
2296 (setq buffer-undo-list
2297 (cons (cons prev-from cur-to
)
2298 (cdr (cdr (cdr buffer-undo-list
))))))))
2299 ;; Implement -post-goto-bullet, if set: (must be after undo business)
2300 (if (and allout-post-goto-bullet
2301 (allout-current-bullet-pos))
2302 (progn (goto-char (allout-current-bullet-pos))
2303 (setq allout-post-goto-bullet nil
)))
2305 ;;;_ > allout-pre-command-business ()
2306 (defun allout-pre-command-business ()
2307 "Outline `pre-command-hook' function for outline buffers.
2308 Implements special behavior when cursor is on bullet character.
2310 When the cursor is on the bullet character, self-insert characters are
2311 reinterpreted as the corresponding control-character in the
2312 `allout-mode-map'. The `allout-mode' `post-command-hook' insures that
2313 the cursor which has moved as a result of such reinterpretation is
2314 positioned on the bullet character of the destination topic.
2316 The upshot is that you can get easy, single (ie, unmodified) key
2317 outline maneuvering operations by positioning the cursor on the bullet
2318 char. When in this mode you can use regular cursor-positioning
2319 command/keystrokes to relocate the cursor off of a bullet character to
2320 return to regular interpretation of self-insert characters."
2321 (if (not (allout-mode-p))
2322 ;; Shouldn't be invoked if not in allout allout-mode, but just in case:
2324 ;; Register isearch status:
2325 (if (and (boundp 'isearch-mode
) isearch-mode
)
2326 (setq allout-pre-was-isearching t
)
2327 (setq allout-pre-was-isearching nil
))
2328 ;; Hot-spot navigation provisions:
2329 (if (and (eq this-command
'self-insert-command
)
2330 (eq (point)(allout-current-bullet-pos)))
2331 (let* ((this-key-num (cond
2332 ((numberp last-command-char
)
2334 ;; XXX Only xemacs has characterp.
2335 ((and (fboundp 'characterp
)
2336 (characterp last-command-char
))
2337 (char-to-int last-command-char
))
2340 (if (zerop this-key-num
)
2342 ; Map upper-register literals
2343 ; to lower register:
2344 (if (<= 96 this-key-num
)
2345 (setq this-key-num
(- this-key-num
32)))
2346 ; Check if we have a literal:
2347 (if (and (<= 64 this-key-num
)
2348 (>= 96 this-key-num
))
2349 (setq mapped-binding
2350 (lookup-key 'allout-mode-map
2351 (concat allout-command-prefix
2352 (char-to-string (- this-key-num
2355 (setq allout-post-goto-bullet t
2356 this-command mapped-binding
)))))))
2357 ;;;_ > allout-find-file-hook ()
2358 (defun allout-find-file-hook ()
2359 "Activate `allout-mode' when `allout-auto-activation' & `allout-layout' are non-nil.
2361 See `allout-init' for setup instructions."
2362 (if (and allout-auto-activation
2363 (not (allout-mode-p))
2366 ;;;_ > allout-isearch-rectification
2367 (defun allout-isearch-rectification ()
2368 "Rectify outline exposure before, during, or after isearch.
2370 Called as part of `allout-post-command-business'."
2372 (let ((isearching (and (boundp 'isearch-mode
) isearch-mode
)))
2373 (cond ((and isearching
(not allout-pre-was-isearching
))
2374 (allout-isearch-expose 'start
))
2375 ((and isearching allout-pre-was-isearching
)
2376 (allout-isearch-expose 'continue
))
2377 ((and (not isearching
) allout-pre-was-isearching
)
2378 (allout-isearch-expose 'final
))
2379 ;; Not and wasn't isearching:
2380 (t (setq allout-isearch-prior-pos nil
)
2381 (setq allout-isearch-did-quit nil
)))))
2382 ;;;_ = allout-isearch-was-font-lock
2383 (defvar allout-isearch-was-font-lock
2384 (and (boundp 'font-lock-mode
) font-lock-mode
))
2386 ;;;_ > allout-flag-region (from to flag)
2387 (defmacro allout-flag-region
(from to flag
)
2388 "Hide or show lines from FROM to TO, via emacs selective-display FLAG char.
2389 Ie, text following flag C-m \(carriage-return) is hidden until the
2390 next C-j (newline) char.
2392 Returns the endpoint of the region."
2393 `(let ((buffer-read-only nil
)
2394 (allout-override-protect t
))
2395 (subst-char-in-region ,from
,to
2396 (if (= ,flag ?
\n) ?
\r ?
\n)
2399 ;;;_ > allout-isearch-expose (mode)
2400 (defun allout-isearch-expose (mode)
2401 "Mode is either 'clear, 'start, 'continue, or 'final."
2402 ;; allout-isearch-prior-pos encodes exposure status of prior pos:
2403 ;; (pos was-vis header-pos end-pos)
2404 ;; pos - point of concern
2405 ;; was-vis - t, else 'topic if entire topic was exposed, 'entry otherwise
2406 ;; Do reclosure or prior pos, as necessary:
2407 (if (eq mode
'start
)
2408 (setq allout-isearch-was-font-lock
(and (boundp 'font-lock-mode
)
2411 (if (eq mode
'final
)
2412 (setq font-lock-mode allout-isearch-was-font-lock
))
2413 (if (and allout-isearch-prior-pos
2414 (listp allout-isearch-prior-pos
))
2415 ;; Conceal prior peek:
2416 (allout-flag-region (car (cdr allout-isearch-prior-pos
))
2417 (car (cdr (cdr allout-isearch-prior-pos
)))
2419 (if (allout-visible-p)
2420 (setq allout-isearch-prior-pos nil
)
2421 (if (not (eq mode
'final
))
2422 (setq allout-isearch-prior-pos
(cons (point) (allout-show-entry)))
2423 (if allout-isearch-did-quit
2425 (setq allout-isearch-prior-pos nil
)
2426 (allout-show-children))))
2427 (setq allout-isearch-did-quit nil
))
2428 ;;;_ > allout-enwrap-isearch ()
2429 (defun allout-enwrap-isearch ()
2430 "Impose `allout-mode' isearch-abort wrapper for dynamic exposure in isearch.
2432 The function checks to ensure that the rebinding is done only once."
2434 (add-hook 'isearch-mode-end-hook
'allout-isearch-rectification
)
2435 (if (fboundp 'allout-real-isearch-abort
)
2438 ; Ensure load of isearch-mode:
2439 (if (or (and (fboundp 'isearch-mode
)
2440 (fboundp 'isearch-abort
))
2441 (condition-case error
2442 (load-library "isearch-mode")
2443 ('file-error
(message
2444 "Skipping isearch-mode provisions - %s '%s'"
2446 (car (cdr (cdr error
))))
2448 ;; Inhibit subsequent tries and return nil:
2449 (setq allout-isearch-dynamic-expose nil
))))
2450 ;; Isearch-mode loaded, encapsulate specific entry points for
2451 ;; outline dynamic-exposure business:
2453 ;; stash crucial isearch-mode funcs under known, private
2454 ;; names, then register wrapper functions under the old
2455 ;; names, in their stead:
2456 (fset 'allout-real-isearch-abort
(symbol-function 'isearch-abort
))
2457 (fset 'isearch-abort
'allout-isearch-abort
)))))
2458 ;;;_ > allout-isearch-abort ()
2459 (defun allout-isearch-abort ()
2460 "Wrapper for `allout-real-isearch-abort' \(which see), to register
2463 (setq allout-isearch-did-quit nil
)
2464 (condition-case what
2465 (allout-real-isearch-abort)
2466 ('quit
(setq allout-isearch-did-quit t
)
2467 (signal 'quit nil
))))
2469 ;;; Prevent unnecessary font-lock while isearching!
2470 (defvar isearch-was-font-locking nil
)
2471 (defun isearch-inhibit-font-lock ()
2472 "Inhibit `font-lock-mode' while isearching - for use on `isearch-mode-hook'."
2473 (if (and (allout-mode-p) (boundp 'font-lock-mode
) font-lock-mode
)
2474 (setq isearch-was-font-locking t
2475 font-lock-mode nil
)))
2476 (add-hook 'isearch-mode-hook
'isearch-inhibit-font-lock
)
2477 (defun isearch-reenable-font-lock ()
2478 "Reenable font-lock after isearching - for use on isearch-mode-end-hook."
2479 (if (and (boundp 'font-lock-mode
) font-lock-mode
)
2480 (if (and (allout-mode-p) isearch-was-font-locking
)
2481 (setq isearch-was-font-locking nil
2482 font-lock-mode t
))))
2483 (add-hook 'isearch-mode-end-hook
'isearch-reenable-font-lock
)
2485 ;;;_ - Topic Format Assessment
2486 ;;;_ > allout-solicit-alternate-bullet (depth &optional current-bullet)
2487 (defun allout-solicit-alternate-bullet (depth &optional current-bullet
)
2489 "Prompt for and return a bullet char as an alternative to the current one.
2491 Offer one suitable for current depth DEPTH as default."
2493 (let* ((default-bullet (or (and (stringp current-bullet
) current-bullet
)
2494 (allout-bullet-for-depth depth
)))
2495 (sans-escapes (regexp-sans-escapes allout-bullets-string
))
2498 (goto-char (allout-current-bullet-pos))
2499 (setq choice
(solicit-char-in-string
2500 (format "Select bullet: %s ('%s' default): "
2506 (if (string= choice
"") default-bullet choice
))
2508 ;;;_ > allout-distinctive-bullet (bullet)
2509 (defun allout-distinctive-bullet (bullet)
2510 "True if bullet is one of those on `allout-distinctive-bullets-string'."
2511 (string-match (regexp-quote bullet
) allout-distinctive-bullets-string
))
2512 ;;;_ > allout-numbered-type-prefix (&optional prefix)
2513 (defun allout-numbered-type-prefix (&optional prefix
)
2514 "True if current header prefix bullet is numbered bullet."
2515 (and allout-numbered-bullet
2516 (string= allout-numbered-bullet
2518 (allout-get-prefix-bullet prefix
)
2519 (allout-get-bullet)))))
2520 ;;;_ > allout-bullet-for-depth (&optional depth)
2521 (defun allout-bullet-for-depth (&optional depth
)
2522 "Return outline topic bullet suited to optional DEPTH, or current depth."
2523 ;; Find bullet in plain-bullets-string modulo DEPTH.
2524 (if allout-stylish-prefixes
2525 (char-to-string (aref allout-plain-bullets-string
2526 (%
(max 0 (- depth
2))
2527 allout-plain-bullets-string-len
)))
2528 allout-primary-bullet
)
2531 ;;;_ - Topic Production
2532 ;;;_ > allout-make-topic-prefix (&optional prior-bullet
2533 (defun allout-make-topic-prefix (&optional prior-bullet
2539 ;; Depth null means use current depth, non-null means we're either
2540 ;; opening a new topic after current topic, lower or higher, or we're
2541 ;; changing level of current topic.
2542 ;; Solicit dominates specified bullet-char.
2544 "Generate a topic prefix suitable for optional arg DEPTH, or current depth.
2546 All the arguments are optional.
2548 PRIOR-BULLET indicates the bullet of the prefix being changed, or
2549 nil if none. This bullet may be preserved (other options
2550 notwithstanding) if it is on the `allout-distinctive-bullets-string',
2553 Second arg NEW indicates that a new topic is being opened after the
2554 topic at point, if non-nil. Default bullet for new topics, eg, may
2555 be set (contingent to other args) to numbered bullets if previous
2556 sibling is one. The implication otherwise is that the current topic
2557 is being adjusted - shifted or rebulleted - and we don't consider
2558 bullet or previous sibling.
2560 Third arg DEPTH forces the topic prefix to that depth, regardless of
2561 the current topics' depth.
2563 If SOLICIT is non-nil, then the choice of bullet is solicited from
2564 user. If it's a character, then that character is offered as the
2565 default, otherwise the one suited to the context \(according to
2566 distinction or depth) is offered. \(This overrides other options,
2567 including, eg, a distinctive PRIOR-BULLET.) If non-nil, then the
2568 context-specific bullet is used.
2570 Fifth arg, NUMBER-CONTROL, matters only if `allout-numbered-bullet'
2571 is non-nil *and* soliciting was not explicitly invoked. Then
2572 NUMBER-CONTROL non-nil forces prefix to either numbered or
2573 denumbered format, depending on the value of the sixth arg, INDEX.
2575 \(Note that NUMBER-CONTROL does *not* apply to level 1 topics. Sorry...)
2577 If NUMBER-CONTROL is non-nil and sixth arg INDEX is non-nil then
2578 the prefix of the topic is forced to be numbered. Non-nil
2579 NUMBER-CONTROL and nil INDEX forces non-numbered format on the
2580 bullet. Non-nil NUMBER-CONTROL and non-nil, non-number INDEX means
2581 that the index for the numbered prefix will be derived, by counting
2582 siblings back to start of level. If INDEX is a number, then that
2583 number is used as the index for the numbered prefix (allowing, eg,
2584 sequential renumbering to not require this function counting back the
2585 index for each successive sibling)."
2587 ;; The options are ordered in likely frequence of use, most common
2588 ;; highest, least lowest. Ie, more likely to be doing prefix
2589 ;; adjustments than soliciting, and yet more than numbering.
2590 ;; Current prefix is least dominant, but most likely to be commonly
2596 (depth (or depth
(allout-depth)))
2597 (header-lead allout-header-prefix
)
2600 ;; Getting value for bullet char is practically the whole job:
2603 ; Simplest situation - level 1:
2604 ((<= depth
1) (setq header-lead
"") allout-primary-bullet
)
2605 ; Simple, too: all asterisks:
2606 (allout-old-style-prefixes
2607 ;; Cheat - make body the whole thing, null out header-lead and
2609 (setq body
(make-string depth
2610 (string-to-char allout-primary-bullet
)))
2611 (setq header-lead
"")
2614 ;; (Neither level 1 nor old-style, so we're space padding.
2615 ;; Sneak it in the condition of the next case, whatever it is.)
2617 ;; Solicitation overrides numbering and other cases:
2618 ((progn (setq body
(make-string (- depth
2) ?\
))
2619 ;; The actual condition:
2621 (let* ((got (allout-solicit-alternate-bullet depth solicit
)))
2622 ;; Gotta check whether we're numbering and got a numbered bullet:
2623 (setq numbering
(and allout-numbered-bullet
2624 (not (and number-control
(not index
)))
2625 (string= got allout-numbered-bullet
)))
2626 ;; Now return what we got, regardless:
2629 ;; Numbering invoked through args:
2630 ((and allout-numbered-bullet number-control
)
2631 (if (setq numbering
(not (setq denumbering
(not index
))))
2632 allout-numbered-bullet
2633 (if (and prior-bullet
2634 (not (string= allout-numbered-bullet
2637 (allout-bullet-for-depth depth
))))
2639 ;;; Neither soliciting nor controlled numbering ;;;
2640 ;;; (may be controlled denumbering, tho) ;;;
2642 ;; Check wrt previous sibling:
2643 ((and new
; only check for new prefixes
2644 (<= depth
(allout-depth))
2645 allout-numbered-bullet
; ... & numbering enabled
2647 (let ((sibling-bullet
2649 ;; Locate correct sibling:
2650 (or (>= depth
(allout-depth))
2651 (allout-ascend-to-depth depth
))
2652 (allout-get-bullet))))
2653 (if (and sibling-bullet
2654 (string= allout-numbered-bullet sibling-bullet
))
2655 (setq numbering sibling-bullet
)))))
2657 ;; Distinctive prior bullet?
2659 (allout-distinctive-bullet prior-bullet
)
2660 ;; Either non-numbered:
2661 (or (not (and allout-numbered-bullet
2662 (string= prior-bullet allout-numbered-bullet
)))
2663 ;; or numbered, and not denumbering:
2664 (setq numbering
(not denumbering
)))
2668 ;; Else, standard bullet per depth:
2669 ((allout-bullet-for-depth depth
)))))
2675 (format "%d" (cond ((and index
(numberp index
)) index
)
2676 (new (1+ (allout-sibling-index depth
)))
2677 ((allout-sibling-index))))))
2680 ;;;_ > allout-open-topic (relative-depth &optional before use_sib_bullet)
2681 (defun allout-open-topic (relative-depth &optional before use_sib_bullet
)
2682 "Open a new topic at depth DEPTH.
2684 New topic is situated after current one, unless optional flag BEFORE
2685 is non-nil, or unless current line is complete empty (not even
2686 whitespace), in which case open is done on current line.
2688 If USE_SIB_BULLET is true, use the bullet of the prior sibling.
2692 - Creation of new topics is with respect to the visible topic
2693 containing the cursor, regardless of intervening concealed ones.
2695 - New headers are generally created after/before the body of a
2696 topic. However, they are created right at cursor location if the
2697 cursor is on a blank line, even if that breaks the current topic
2698 body. This is intentional, to provide a simple means for
2699 deliberately dividing topic bodies.
2701 - Double spacing of topic lists is preserved. Also, the first
2702 level two topic is created double-spaced (and so would be
2703 subsequent siblings, if that's left intact). Otherwise,
2704 single-spacing is used.
2706 - Creation of sibling or nested topics is with respect to the topic
2707 you're starting from, even when creating backwards. This way you
2708 can easily create a sibling in front of the current topic without
2709 having to go to its preceding sibling, and then open forward
2712 (let* ((depth (+ (allout-current-depth) relative-depth
))
2713 (opening-on-blank (if (looking-at "^\$")
2714 (not (setq before nil
))))
2715 opening-numbered
; Will get while computing ref-topic, below
2716 ref-depth
; Will get while computing ref-topic, below
2717 ref-bullet
; Will get while computing ref-topic, next
2718 (ref-topic (save-excursion
2719 (cond ((< relative-depth
0)
2720 (allout-ascend-to-depth depth
))
2721 ((>= relative-depth
1) nil
)
2722 (t (allout-back-to-current-heading)))
2723 (setq ref-depth
(allout-recent-depth))
2725 (if (> allout-recent-prefix-end
1)
2726 (allout-recent-bullet)
2728 (setq opening-numbered
2730 (and allout-numbered-bullet
2731 (or (<= relative-depth
0)
2732 (allout-descend-to-depth depth
))
2733 (if (allout-numbered-type-prefix)
2734 allout-numbered-bullet
))))
2739 (if (not opening-on-blank
)
2740 ; Positioning and vertical
2741 ; padding - only if not
2744 (goto-char ref-topic
)
2745 (setq dbl-space
; Determine double space action:
2746 (or (and (<= relative-depth
0) ; not descending;
2748 ;; at b-o-b or preceded by a blank line?
2749 (or (> 0 (forward-line -
1))
2750 (looking-at "^\\s-*$")
2753 ;; succeeded by a blank line?
2754 (allout-end-of-current-subtree)
2756 (and (= ref-depth
1)
2760 ;; Don't already have following
2761 ;; vertical padding:
2762 (not (allout-pre-next-preface)))))))
2764 ; Position to prior heading,
2765 ; if inserting backwards, and
2766 ; not going outwards:
2767 (if (and before
(>= relative-depth
0))
2768 (progn (allout-back-to-current-heading)
2769 (setq doing-beginning
(bobp))
2771 (allout-previous-heading)))
2772 (if (and before
(bobp))
2773 (allout-unprotected (open-line 1))))
2775 (if (<= relative-depth
0)
2776 ;; Not going inwards, don't snug up:
2778 (allout-unprotected (open-line (if dbl-space
2 1)))
2780 (progn (end-of-line)
2781 (allout-pre-next-preface)
2782 (while (= ?
\r (following-char))
2784 (if (not (looking-at "^$"))
2785 (allout-unprotected (open-line 1))))
2786 (allout-end-of-current-subtree)))
2787 ;; Going inwards - double-space if first offspring is,
2788 ;; otherwise snug up.
2789 (end-of-line) ; So we skip any concealed progeny.
2790 (allout-pre-next-preface)
2792 ;; Blank lines between current header body and next
2793 ;; header - get to last substantive (non-white-space)
2795 (re-search-backward "[^ \t\n]" nil t
))
2797 (allout-next-heading)
2798 (if (> (allout-recent-depth) ref-depth
)
2799 ;; This is an offspring.
2800 (progn (forward-line -
1)
2801 (looking-at "^\\s-*$"))))
2802 (progn (forward-line 1)
2803 (allout-unprotected (open-line 1))))
2805 ;;(if doing-beginning (goto-char doing-beginning))
2807 (progn (if (and (not (> depth ref-depth
))
2809 (allout-unprotected (open-line 1))
2810 (if (> depth ref-depth
)
2811 (allout-unprotected (newline 1))
2813 (allout-unprotected (open-line 1))
2815 (allout-unprotected (newline 1))))))
2817 (allout-unprotected (newline 1)))
2818 (if (and (not (eobp))
2822 (insert (concat (allout-make-topic-prefix opening-numbered
2827 ;;(if doing-beginning (save-excursion (newline (if dbl-space 2 1))))
2830 (allout-rebullet-heading (and use_sib_bullet ref-bullet
);;; solicit
2832 nil
;;; number-control
2837 ;;;_ . open-topic contingencies
2838 ;;;_ ; base topic - one from which open was issued
2839 ;;;_ , beginning char
2840 ;;;_ , amount of space before will be used, unless opening in place
2841 ;;;_ , end char will be used, unless opening before (and it still may)
2842 ;;;_ ; absolute depth of new topic
2843 ;;;_ ! insert in place - overrides most stuff
2844 ;;;_ ; relative depth of new re base
2845 ;;;_ ; before or after base topic
2846 ;;;_ ; spacing around topic, if any, prior to new topic and at same depth
2847 ;;;_ ; buffer boundaries - special provisions for beginning and end ob
2848 ;;;_ ; level 1 topics have special provisions also - double space.
2849 ;;;_ ; location of new topic
2850 ;;;_ > allout-open-subtopic (arg)
2851 (defun allout-open-subtopic (arg)
2852 "Open new topic header at deeper level than the current one.
2854 Negative universal arg means to open deeper, but place the new topic
2855 prior to the current one."
2857 (allout-open-topic 1 (> 0 arg
)))
2858 ;;;_ > allout-open-sibtopic (arg)
2859 (defun allout-open-sibtopic (arg)
2860 "Open new topic header at same level as the current one.
2862 Positive universal arg means to use the bullet of the prior sibling.
2864 Negative universal arg means to place the new topic prior to the current
2867 (allout-open-topic 0 (> 0 arg
) (< 1 arg
)))
2868 ;;;_ > allout-open-supertopic (arg)
2869 (defun allout-open-supertopic (arg)
2870 "Open new topic header at shallower level than the current one.
2872 Negative universal arg means to open shallower, but place the new
2873 topic prior to the current one."
2876 (allout-open-topic -
1 (> 0 arg
)))
2878 ;;;_ - Outline Alteration
2879 ;;;_ : Topic Modification
2880 ;;;_ = allout-former-auto-filler
2881 (defvar allout-former-auto-filler nil
2882 "Name of modal fill function being wrapped by `allout-auto-fill'.")
2883 ;;;_ > allout-auto-fill ()
2884 (defun allout-auto-fill ()
2885 "`allout-mode' autofill function.
2887 Maintains outline hanging topic indentation if
2888 `allout-use-hanging-indents' is set."
2889 (let ((fill-prefix (if allout-use-hanging-indents
2890 ;; Check for topic header indentation:
2893 (if (looking-at allout-regexp
)
2894 ;; ... construct indentation to account for
2895 ;; length of topic prefix:
2896 (make-string (progn (allout-end-of-prefix)
2899 (if (or allout-former-auto-filler allout-use-hanging-indents
)
2901 ;;;_ > allout-reindent-body (old-depth new-depth &optional number)
2902 (defun allout-reindent-body (old-depth new-depth
&optional number
)
2903 "Reindent body lines which were indented at old-depth to new-depth.
2905 Optional arg NUMBER indicates numbering is being added, and it must
2908 Note that refill of indented paragraphs is not done."
2911 (allout-end-of-prefix)
2912 (let* ((new-margin (current-column))
2913 excess old-indent-begin old-indent-end
2915 ;; We want the column where the header-prefix text started
2916 ;; *before* the prefix was changed, so we infer it relative
2917 ;; to the new margin and the shift in depth:
2918 (old-margin (+ old-depth
(- new-margin new-depth
))))
2920 ;; Process lines up to (but excluding) next topic header:
2924 (and (re-search-forward "[\n\r]\\(\\s-*\\)"
2927 ;; Register the indent data, before we reset the
2928 ;; match data with a subsequent `looking-at':
2929 (setq old-indent-begin
(match-beginning 1)
2930 old-indent-end
(match-end 1))
2931 (not (looking-at allout-regexp
)))
2932 (if (> 0 (setq excess
(- (current-column)
2934 ;; Text starts left of old margin - don't adjust:
2936 ;; Text was hanging at or right of old left margin -
2937 ;; reindent it, preserving its existing indentation
2938 ;; beyond the old margin:
2939 (delete-region old-indent-begin old-indent-end
)
2940 (indent-to (+ new-margin excess
)))))))))
2941 ;;;_ > allout-rebullet-current-heading (arg)
2942 (defun allout-rebullet-current-heading (arg)
2943 "Solicit new bullet for current visible heading."
2945 (let ((initial-col (current-column))
2946 (on-bullet (eq (point)(allout-current-bullet-pos)))
2947 (backwards (if (< arg
0)
2948 (setq arg
(* arg -
1)))))
2950 (save-excursion (allout-back-to-current-heading)
2951 (allout-end-of-prefix)
2952 (allout-rebullet-heading t
;;; solicit
2954 nil
;;; number-control
2956 t
)) ;;; do-successors
2960 (setq initial-col nil
) ; Override positioning back to init col
2962 (allout-next-visible-heading 1)
2963 (allout-goto-prefix)
2964 (allout-next-visible-heading -
1))))
2966 (cond (on-bullet (goto-char (allout-current-bullet-pos)))
2967 (initial-col (move-to-column initial-col
)))))
2968 ;;;_ > allout-rebullet-heading (&optional solicit ...)
2969 (defun allout-rebullet-heading (&optional solicit
2975 "Adjust bullet of current topic prefix.
2977 All args are optional.
2979 If SOLICIT is non-nil, then the choice of bullet is solicited from
2980 user. If it's a character, then that character is offered as the
2981 default, otherwise the one suited to the context \(according to
2982 distinction or depth) is offered. If non-nil, then the
2983 context-specific bullet is just used.
2985 Second arg DEPTH forces the topic prefix to that depth, regardless
2986 of the topic's current depth.
2988 Third arg NUMBER-CONTROL can force the prefix to or away from
2989 numbered form. It has effect only if `allout-numbered-bullet' is
2990 non-nil and soliciting was not explicitly invoked (via first arg).
2991 Its effect, numbering or denumbering, then depends on the setting
2992 of the fourth arg, INDEX.
2994 If NUMBER-CONTROL is non-nil and fourth arg INDEX is nil, then the
2995 prefix of the topic is forced to be non-numbered. Null index and
2996 non-nil NUMBER-CONTROL forces denumbering. Non-nil INDEX (and
2997 non-nil NUMBER-CONTROL) forces a numbered-prefix form. If non-nil
2998 INDEX is a number, then that number is used for the numbered
2999 prefix. Non-nil and non-number means that the index for the
3000 numbered prefix will be derived by `allout-make-topic-prefix'.
3002 Fifth arg DO-SUCCESSORS t means re-resolve count on succeeding
3005 Cf vars `allout-stylish-prefixes', `allout-old-style-prefixes',
3006 and `allout-numbered-bullet', which all affect the behavior of
3009 (let* ((current-depth (allout-depth))
3010 (new-depth (or new-depth current-depth
))
3011 (mb allout-recent-prefix-beginning
)
3012 (me allout-recent-prefix-end
)
3013 (current-bullet (buffer-substring (- me
1) me
))
3014 (new-prefix (allout-make-topic-prefix current-bullet
3021 ;; Is new one is identical to old?
3022 (if (and (= current-depth new-depth
)
3023 (string= current-bullet
3024 (substring new-prefix
(1- (length new-prefix
)))))
3028 ;; New prefix probably different from old:
3029 ; get rid of old one:
3030 (allout-unprotected (delete-region mb me
))
3032 ; Dispense with number if
3033 ; numbered-bullet prefix:
3034 (if (and allout-numbered-bullet
3035 (string= allout-numbered-bullet current-bullet
)
3036 (looking-at "[0-9]+"))
3038 (delete-region (match-beginning 0)(match-end 0))))
3040 ; Put in new prefix:
3041 (allout-unprotected (insert new-prefix
))
3043 ;; Reindent the body if elected and margin changed:
3044 (if (and allout-reindent-bodies
3045 (not (= new-depth current-depth
)))
3046 (allout-reindent-body current-depth new-depth
))
3048 ;; Recursively rectify successive siblings of orig topic if
3049 ;; caller elected for it:
3052 (while (allout-next-sibling new-depth nil
)
3054 (cond ((numberp index
) (1+ index
))
3055 ((not number-control
) (allout-sibling-index))))
3056 (if (allout-numbered-type-prefix)
3057 (allout-rebullet-heading nil
;;; solicit
3058 new-depth
;;; new-depth
3059 number-control
;;; number-control
3061 nil
))))) ;;;(dont!)do-successors
3062 ) ; (if (and (= current-depth new-depth)...))
3063 ) ; let* ((current-depth (allout-depth))...)
3065 ;;;_ > allout-rebullet-topic (arg)
3066 (defun allout-rebullet-topic (arg)
3067 "Like `allout-rebullet-topic-grunt', but start from topic visible at point.
3069 Descends into invisible as well as visible topics, however.
3071 With repeat count, shift topic depth by that amount."
3073 (let ((start-col (current-column))
3077 (cond ((null arg
) (setq arg
0))
3078 ((listp arg
) (setq arg
(car arg
))))
3079 ;; Fill the user in, in case we're shifting a big topic:
3080 (if (not (zerop arg
)) (message "Shifting..."))
3081 (allout-back-to-current-heading)
3082 (if (<= (+ (allout-recent-depth) arg
) 0)
3083 (error "Attempt to shift topic below level 1"))
3084 (allout-rebullet-topic-grunt arg
)
3085 (if (not (zerop arg
)) (message "Shifting... done.")))
3086 (move-to-column (max 0 (+ start-col arg
)))))
3087 ;;;_ > allout-rebullet-topic-grunt (&optional relative-depth ...)
3088 (defun allout-rebullet-topic-grunt (&optional relative-depth
3094 "Rebullet the topic at point, visible or invisible, and all
3095 contained subtopics. See `allout-rebullet-heading' for rebulleting
3098 All arguments are optional.
3100 First arg RELATIVE-DEPTH means to shift the depth of the entire
3103 The rest of the args are for internal recursive use by the function
3104 itself. The are STARTING-DEPTH, STARTING-POINT, and INDEX."
3106 (let* ((relative-depth (or relative-depth
0))
3107 (new-depth (allout-depth))
3108 (starting-depth (or starting-depth new-depth
))
3109 (on-starting-call (null starting-point
))
3111 ;; Leave index null on starting call, so rebullet-heading
3112 ;; calculates it at what might be new depth:
3113 (and (or (zerop relative-depth
)
3114 (not on-starting-call
))
3115 (allout-sibling-index))))
3116 (moving-outwards (< 0 relative-depth
))
3117 (starting-point (or starting-point
(point))))
3119 ;; Sanity check for excessive promotion done only on starting call:
3120 (and on-starting-call
3122 (> 0 (+ starting-depth relative-depth
))
3123 (error "Attempt to shift topic out beyond level 1")) ;;; ====>
3125 (cond ((= starting-depth new-depth
)
3126 ;; We're at depth to work on this one:
3127 (allout-rebullet-heading nil
;;; solicit
3128 (+ starting-depth
;;; starting-depth
3132 ;; Every contained topic will get hit,
3133 ;; and we have to get to outside ones
3135 nil
) ;;; do-successors
3136 ;; ... and work on subsequent ones which are at greater depth:
3138 (allout-next-heading)
3139 (while (and (not (eobp))
3140 (< starting-depth
(allout-recent-depth)))
3141 (setq index
(1+ index
))
3142 (allout-rebullet-topic-grunt relative-depth
;;; relative-depth
3143 (1+ starting-depth
);;;starting-depth
3144 starting-point
;;; starting-point
3147 ((< starting-depth new-depth
)
3148 ;; Rare case - subtopic more than one level deeper than parent.
3149 ;; Treat this one at an even deeper level:
3150 (allout-rebullet-topic-grunt relative-depth
;;; relative-depth
3151 new-depth
;;; starting-depth
3152 starting-point
;;; starting-point
3155 (if on-starting-call
3157 ;; Rectify numbering of former siblings of the adjusted topic,
3158 ;; if topic has changed depth
3159 (if (or do-successors
3160 (and (not (zerop relative-depth
))
3161 (or (= (allout-recent-depth) starting-depth
)
3162 (= (allout-recent-depth) (+ starting-depth
3164 (allout-rebullet-heading nil nil nil nil t
))
3165 ;; Now rectify numbering of new siblings of the adjusted topic,
3166 ;; if depth has been changed:
3167 (progn (goto-char starting-point
)
3168 (if (not (zerop relative-depth
))
3169 (allout-rebullet-heading nil nil nil nil t
)))))
3172 ;;;_ > allout-renumber-to-depth (&optional depth)
3173 (defun allout-renumber-to-depth (&optional depth
)
3174 "Renumber siblings at current depth.
3176 Affects superior topics if optional arg DEPTH is less than current depth.
3178 Returns final depth."
3180 ;; Proceed by level, processing subsequent siblings on each,
3181 ;; ascending until we get shallower than the start depth:
3183 (let ((ascender (allout-depth))
3185 (while (and (not (eobp))
3187 (>= (allout-recent-depth) depth
)
3188 (>= ascender depth
))
3189 ; Skip over all topics at
3190 ; lesser depths, which can not
3191 ; have been disturbed:
3192 (while (and (not (setq was-eobp
(eobp)))
3193 (> (allout-recent-depth) ascender
))
3194 (allout-next-heading))
3195 ; Prime ascender for ascension:
3196 (setq ascender
(1- (allout-recent-depth)))
3197 (if (>= (allout-recent-depth) depth
)
3198 (allout-rebullet-heading nil
;;; solicit
3200 nil
;;; number-control
3202 t
)) ;;; do-successors
3203 (if was-eobp
(goto-char (point-max)))))
3204 (allout-recent-depth))
3205 ;;;_ > allout-number-siblings (&optional denumber)
3206 (defun allout-number-siblings (&optional denumber
)
3207 "Assign numbered topic prefix to this topic and its siblings.
3209 With universal argument, denumber - assign default bullet to this
3210 topic and its siblings.
3212 With repeated universal argument (`^U^U'), solicit bullet for each
3213 rebulleting each topic at this level."
3218 (allout-back-to-current-heading)
3219 (allout-beginning-of-level)
3220 (let ((depth (allout-recent-depth))
3221 (index (if (not denumber
) 1))
3222 (use-bullet (equal '(16) denumber
))
3225 (allout-rebullet-heading use-bullet
;;; solicit
3227 t
;;; number-control
3229 nil
) ;;; do-successors
3230 (if index
(setq index
(1+ index
)))
3231 (setq more
(allout-next-sibling depth nil
))))))
3232 ;;;_ > allout-shift-in (arg)
3233 (defun allout-shift-in (arg)
3234 "Increase depth of current heading and any topics collapsed within it."
3236 (allout-rebullet-topic arg
))
3237 ;;;_ > allout-shift-out (arg)
3238 (defun allout-shift-out (arg)
3239 "Decrease depth of current heading and any topics collapsed within it."
3241 (allout-rebullet-topic (* arg -
1)))
3242 ;;;_ : Surgery (kill-ring) functions with special provisions for outlines:
3243 ;;;_ > allout-kill-line (&optional arg)
3244 (defun allout-kill-line (&optional arg
)
3245 "Kill line, adjusting subsequent lines suitably for outline mode."
3248 (if (not (and (allout-mode-p) ; active outline mode,
3249 allout-numbered-bullet
; numbers may need adjustment,
3250 (bolp) ; may be clipping topic head,
3251 (looking-at allout-regexp
))) ; are clipping topic head.
3252 ;; Above conditions do not obtain - just do a regular kill:
3254 ;; Ah, have to watch out for adjustments:
3255 (let* ((depth (allout-depth)))
3258 ; Provide some feedback:
3261 ; Start with the topic
3262 ; following killed line:
3263 (if (not (looking-at allout-regexp
))
3264 (allout-next-heading))
3265 (allout-renumber-to-depth depth
)))))
3266 ;;;_ > allout-kill-topic ()
3267 (defun allout-kill-topic ()
3268 "Kill topic together with subtopics.
3270 Leaves primary topic's trailing vertical whitespace, if any."
3272 ;; Some finagling is done to make complex topic kills appear faster
3273 ;; than they actually are. A redisplay is performed immediately
3274 ;; after the region is disposed of, though the renumbering process
3275 ;; has yet to be performed. This means that there may appear to be
3276 ;; a lag *after* the kill has been performed.
3279 (let* ((beg (prog1 (allout-back-to-current-heading)(beginning-of-line)))
3280 (depth (allout-recent-depth)))
3281 (allout-end-of-current-subtree)
3283 (if (or (not (looking-at "^$"))
3284 ;; A blank line - cut it with this topic *unless* this
3285 ;; is the last topic at this level, in which case
3286 ;; we'll leave the blank line as part of the
3287 ;; containing topic:
3289 (and (allout-next-heading)
3290 (>= (allout-recent-depth) depth
))))
3293 (kill-region beg
(point))
3296 (allout-renumber-to-depth depth
))))
3297 ;;;_ > allout-yank-processing ()
3298 (defun allout-yank-processing (&optional arg
)
3300 "Incidental outline specific business to be done just after text yanks.
3302 Does depth adjustment of yanked topics, when:
3304 1 the stuff being yanked starts with a valid outline header prefix, and
3305 2 it is being yanked at the end of a line which consists of only a valid
3308 Also, adjusts numbering of subsequent siblings when appropriate.
3310 Depth adjustment alters the depth of all the topics being yanked
3311 the amount it takes to make the first topic have the depth of the
3312 header into which it's being yanked.
3314 The point is left in front of yanked, adjusted topics, rather than
3315 at the end (and vice-versa with the mark). Non-adjusted yanks,
3316 however, are left exactly like normal, not outline specific yanks."
3319 ; Get to beginning, leaving
3320 ; region around subject:
3321 (if (< (my-mark-marker t
) (point))
3322 (exchange-point-and-mark))
3323 (let* ((subj-beg (point))
3324 (subj-end (my-mark-marker t
))
3325 ;; 'resituate' if yanking an entire topic into topic header:
3326 (resituate (and (allout-e-o-prefix-p)
3327 (looking-at (concat "\\(" allout-regexp
"\\)"))
3328 (allout-prefix-data (match-beginning 1)
3330 ;; `rectify-numbering' if resituating (where several topics may
3331 ;; be resituating) or yanking a topic into a topic slot (bol):
3332 (rectify-numbering (or resituate
3333 (and (bolp) (looking-at allout-regexp
)))))
3335 ; The yanked stuff is a topic:
3336 (let* ((prefix-len (- (match-end 1) subj-beg
))
3337 (subj-depth (allout-recent-depth))
3338 (prefix-bullet (allout-recent-bullet))
3340 ;; Nil if adjustment unnecessary, otherwise depth to which
3341 ;; adjustment should be made:
3343 (and (goto-char subj-end
)
3345 (goto-char subj-beg
)
3346 (and (looking-at allout-regexp
)
3349 (not (= (point) subj-beg
)))
3350 (looking-at allout-regexp
)
3351 (allout-prefix-data (match-beginning 0)
3353 (allout-recent-depth))))
3356 (setq rectify-numbering allout-numbered-bullet
)
3358 ; Do the adjustment:
3360 (message "... yanking") (sit-for 0)
3362 (narrow-to-region subj-beg subj-end
)
3363 ; Trim off excessive blank
3364 ; line at end, if any:
3365 (goto-char (point-max))
3366 (if (looking-at "^$")
3367 (allout-unprotected (delete-char -
1)))
3368 ; Work backwards, with each
3370 ; successively excluding the
3371 ; last processed topic from
3372 ; the narrow region:
3374 (allout-back-to-current-heading)
3375 ; go as high as we can in each bunch:
3376 (while (allout-ascend-to-depth (1- (allout-depth))))
3378 (allout-rebullet-topic-grunt (- adjust-to-depth
3381 (if (setq more
(not (bobp)))
3384 (narrow-to-region subj-beg
(point))))))
3386 ;; Preserve new bullet if it's a distinctive one, otherwise
3388 (if (string-match (regexp-quote prefix-bullet
)
3389 allout-distinctive-bullets-string
)
3390 ; Delete from bullet of old to
3391 ; before bullet of new:
3394 (delete-region (point) subj-beg
)
3395 (set-marker (my-mark-marker t
) subj-end
)
3396 (goto-char subj-beg
)
3397 (allout-end-of-prefix))
3398 ; Delete base subj prefix,
3400 (delete-region (point) (+ (point)
3402 (- adjust-to-depth subj-depth
)))
3403 ; and delete residual subj
3404 ; prefix digits and space:
3405 (while (looking-at "[0-9]") (delete-char 1))
3406 (if (looking-at " ") (delete-char 1))))
3407 (exchange-point-and-mark))))
3408 (if rectify-numbering
3411 ; Give some preliminary feedback:
3412 (message "... reconciling numbers") (sit-for 0)
3413 ; ... and renumber, in case necessary:
3414 (goto-char subj-beg
)
3415 (if (allout-goto-prefix)
3416 (allout-rebullet-heading nil
;;; solicit
3417 (allout-depth) ;;; depth
3418 nil
;;; number-control
3423 (exchange-point-and-mark))))
3424 ;;;_ > allout-yank (&optional arg)
3425 (defun allout-yank (&optional arg
)
3426 "`allout-mode' yank, with depth and numbering adjustment of yanked topics.
3428 Non-topic yanks work no differently than normal yanks.
3430 If a topic is being yanked into a bare topic prefix, the depth of the
3431 yanked topic is adjusted to the depth of the topic prefix.
3433 1 we're yanking in an `allout-mode' buffer
3434 2 the stuff being yanked starts with a valid outline header prefix, and
3435 3 it is being yanked at the end of a line which consists of only a valid
3438 If these conditions hold then the depth of the yanked topics are all
3439 adjusted the amount it takes to make the first one at the depth of the
3440 header into which it's being yanked.
3442 The point is left in front of yanked, adjusted topics, rather than
3443 at the end (and vice-versa with the mark). Non-adjusted yanks,
3444 however, (ones that don't qualify for adjustment) are handled
3445 exactly like normal yanks.
3447 Numbering of yanked topics, and the successive siblings at the depth
3448 into which they're being yanked, is adjusted.
3450 `allout-yank-pop' works with `allout-yank' just like normal yank-pop
3451 works with normal yank in non-outline buffers."
3454 (setq this-command
'yank
)
3457 (allout-yank-processing)))
3458 ;;;_ > allout-yank-pop (&optional arg)
3459 (defun allout-yank-pop (&optional arg
)
3460 "Yank-pop like `allout-yank' when popping to bare outline prefixes.
3462 Adapts level of popped topics to level of fresh prefix.
3464 Note - prefix changes to distinctive bullets will stick, if followed
3465 by pops to non-distinctive yanks. Bug..."
3468 (setq this-command
'yank
)
3471 (allout-yank-processing)))
3473 ;;;_ - Specialty bullet functions
3474 ;;;_ : File Cross references
3475 ;;;_ > allout-resolve-xref ()
3476 (defun allout-resolve-xref ()
3477 "Pop to file associated with current heading, if it has an xref bullet.
3479 \(Works according to setting of `allout-file-xref-bullet')."
3481 (if (not allout-file-xref-bullet
)
3483 "outline cross references disabled - no `allout-file-xref-bullet'")
3484 (if (not (string= (allout-current-bullet) allout-file-xref-bullet
))
3485 (error "current heading lacks cross-reference bullet `%s'"
3486 allout-file-xref-bullet
)
3489 (let* ((text-start allout-recent-prefix-end
)
3490 (heading-end (progn (end-of-line) (point))))
3491 (goto-char text-start
)
3493 (if (re-search-forward "\\s-\\(\\S-*\\)" heading-end t
)
3494 (buffer-substring (match-beginning 1) (match-end 1))))))
3496 (if (not (= (aref file-name
0) ?
:))
3497 (expand-file-name file-name
)
3498 ; A registry-files ref, strip the `:'
3499 ; and try to follow it:
3500 (let ((reg-ref (reference-registered-file
3501 (substring file-name
1) nil t
)))
3502 (if reg-ref
(car (cdr reg-ref
))))))
3503 (if (or (file-exists-p file-name
)
3504 (if (file-writable-p file-name
)
3505 (y-or-n-p (format "%s not there, create one? "
3507 (error "%s not found and can't be created" file-name
)))
3508 (condition-case failure
3509 (find-file-other-window file-name
)
3511 (error "%s not found" file-name
))
3517 ;;;_ #6 Exposure Control
3520 ;;;_ > allout-flag-current-subtree (flag)
3521 (defun allout-flag-current-subtree (flag)
3522 "Hide or show subtree of currently-visible topic.
3524 See `allout-flag-region' for more details."
3527 (allout-back-to-current-heading)
3528 (allout-flag-region (point)
3529 (progn (allout-end-of-current-subtree) (1- (point)))
3532 ;;;_ - Topic-specific
3533 ;;;_ > allout-show-entry ()
3534 (defun allout-show-entry ()
3535 "Like `allout-show-current-entry', reveals entries nested in hidden topics.
3537 This is a way to give restricted peek at a concealed locality without the
3538 expense of exposing its context, but can leave the outline with aberrant
3539 exposure. `allout-hide-current-entry-completely' or `allout-show-to-offshoot'
3540 should be used after the peek to rectify the exposure."
3546 (allout-goto-prefix)
3547 (setq beg
(if (= (preceding-char) ?
\r) (1- (point)) (point)))
3548 (re-search-forward "[\n\r]" nil t
)
3549 (setq end
(1- (if (< at
(point))
3550 ;; We're on topic head line - show only it:
3552 ;; or we're in body - include it:
3553 (max beg
(or (allout-pre-next-preface) (point))))))
3554 (allout-flag-region beg end ?
\n)
3556 ;;;_ > allout-show-children (&optional level strict)
3557 (defun allout-show-children (&optional level strict
)
3559 "If point is visible, show all direct subheadings of this heading.
3561 Otherwise, do `allout-show-to-offshoot', and then show subheadings.
3563 Optional LEVEL specifies how many levels below the current level
3564 should be shown, or all levels if t. Default is 1.
3566 Optional STRICT means don't resort to -show-to-offshoot, no matter
3567 what. This is basically so -show-to-offshoot, which is called by
3568 this function, can employ the pure offspring-revealing capabilities of
3571 Returns point at end of subtree that was opened, if any. (May get a
3572 point of non-opened subtree?)"
3576 (if (and (not strict
)
3579 (progn (allout-show-to-offshoot) ; Point's concealed, open to
3581 ;; Then recurse, but with "strict" set so we don't
3582 ;; infinite regress:
3583 (setq max-pos
(allout-show-children level t
)))
3587 (let* ((start-pt (point))
3588 (chart (allout-chart-subtree (or level
1)))
3589 (to-reveal (allout-chart-to-reveal chart
(or level
1))))
3590 (goto-char start-pt
)
3591 (if (and strict
(= (preceding-char) ?
\r))
3592 ;; Concealed root would already have been taken care of,
3593 ;; unless strict was set.
3595 (allout-flag-region (point) (allout-snug-back) ?
\n)
3596 (if allout-show-bodies
3597 (progn (goto-char (car to-reveal
))
3598 (allout-show-current-entry)))))
3600 (goto-char (car to-reveal
))
3601 (allout-flag-region (point) (allout-snug-back) ?
\n)
3602 (if allout-show-bodies
3603 (progn (goto-char (car to-reveal
))
3604 (allout-show-current-entry)))
3605 (setq to-reveal
(cdr to-reveal
)))))))))
3606 ;;;_ > allout-hide-point-reconcile ()
3607 (defun allout-hide-reconcile ()
3608 "Like `allout-hide-current-entry'; hides completely if within hidden region.
3610 Specifically intended for aberrant exposure states, like entries that were
3611 exposed by `allout-show-entry' but are within otherwise concealed regions."
3614 (allout-goto-prefix)
3615 (allout-flag-region (if (not (bobp)) (1- (point)) (point))
3616 (progn (allout-pre-next-preface)
3617 (if (= ?
\r (following-char))
3621 ;;;_ > allout-show-to-offshoot ()
3622 (defun allout-show-to-offshoot ()
3623 "Like `allout-show-entry', but reveals all concealed ancestors, as well.
3625 As with `allout-hide-current-entry-completely', useful for rectifying
3626 aberrant exposure states produced by `allout-show-entry'."
3630 (let ((orig-pt (point))
3631 (orig-pref (allout-goto-prefix))
3634 (while (or bag-it
(= (preceding-char) ?
\r))
3636 (if (= last-at
(setq last-at
(point)))
3637 ;; Oops, we're not making any progress! Show the current
3638 ;; topic completely, and bag this try.
3639 (progn (beginning-of-line)
3640 (allout-show-current-subtree)
3645 "allout-show-to-offshoot: "
3646 "Aberrant nesting encountered.")))
3647 (allout-show-children)
3648 (goto-char orig-pref
))
3649 (goto-char orig-pt
)))
3650 (if (allout-hidden-p)
3651 (allout-show-entry)))
3652 ;;;_ > allout-hide-current-entry ()
3653 (defun allout-hide-current-entry ()
3654 "Hide the body directly following this heading."
3656 (allout-back-to-current-heading)
3658 (allout-flag-region (point)
3659 (progn (allout-end-of-current-entry) (point))
3661 ;;;_ > allout-show-current-entry (&optional arg)
3662 (defun allout-show-current-entry (&optional arg
)
3664 "Show body following current heading, or hide the entry if repeat count."
3668 (allout-hide-current-entry)
3670 (allout-flag-region (point)
3671 (progn (allout-end-of-current-entry) (point))
3673 ;;;_ > allout-hide-current-entry-completely ()
3674 ; ... allout-hide-current-entry-completely also for isearch dynamic exposure:
3675 (defun allout-hide-current-entry-completely ()
3676 "Like `allout-hide-current-entry', but conceal topic completely.
3678 Specifically intended for aberrant exposure states, like entries that were
3679 exposed by `allout-show-entry' but are within otherwise concealed regions."
3682 (allout-goto-prefix)
3683 (allout-flag-region (if (not (bobp)) (1- (point)) (point))
3684 (progn (allout-pre-next-preface)
3685 (if (= ?
\r (following-char))
3689 ;;;_ > allout-show-current-subtree (&optional arg)
3690 (defun allout-show-current-subtree (&optional arg
)
3691 "Show everything within the current topic. With a repeat-count,
3692 expose this topic and its siblings."
3695 (if (<= (allout-current-depth) 0)
3696 ;; Outside any topics - try to get to the first:
3697 (if (not (allout-next-heading))
3699 ;; got to first, outermost topic - set to expose it and siblings:
3700 (message "Above outermost topic - exposing all.")
3701 (allout-flag-region (point-min)(point-max) ?
\n))
3703 (allout-flag-current-subtree ?
\n)
3704 (allout-beginning-of-level)
3705 (allout-expose-topic '(* :))))))
3706 ;;;_ > allout-hide-current-subtree (&optional just-close)
3707 (defun allout-hide-current-subtree (&optional just-close
)
3708 "Close the current topic, or containing topic if this one is already closed.
3710 If this topic is closed and it's a top level topic, close this topic
3713 If optional arg JUST-CLOSE is non-nil, do not treat the parent or
3714 siblings, even if the target topic is already closed."
3717 (let ((from (point))
3718 (orig-eol (progn (end-of-line)
3719 (if (not (allout-goto-prefix))
3720 (error "No topics found")
3721 (end-of-line)(point)))))
3722 (allout-flag-current-subtree ?
\r)
3724 (if (and (= orig-eol
(progn (goto-char orig-eol
)
3728 ;; Structure didn't change - try hiding current level:
3730 (if (allout-up-current-level 1 t
)
3734 "Top-level topic already closed - closing siblings..."))
3736 (allout-expose-topic '(0 :))
3737 (message (concat msg
" Done.")))
3739 (/= (allout-recent-depth) 0))
3740 (allout-hide-current-subtree))
3742 ;;;_ > allout-show-current-branches ()
3743 (defun allout-show-current-branches ()
3744 "Show all subheadings of this heading, but not their bodies."
3747 (allout-show-children t
))
3748 ;;;_ > allout-hide-current-leaves ()
3749 (defun allout-hide-current-leaves ()
3750 "Hide the bodies of the current topic and all its offspring."
3752 (allout-back-to-current-heading)
3753 (allout-hide-region-body (point) (progn (allout-end-of-current-subtree)
3756 ;;;_ - Region and beyond
3757 ;;;_ > allout-show-all ()
3758 (defun allout-show-all ()
3759 "Show all of the text in the buffer."
3761 (message "Exposing entire buffer...")
3762 (allout-flag-region (point-min) (point-max) ?
\n)
3763 (message "Exposing entire buffer... Done."))
3764 ;;;_ > allout-hide-bodies ()
3765 (defun allout-hide-bodies ()
3766 "Hide all of buffer except headings."
3768 (allout-hide-region-body (point-min) (point-max)))
3769 ;;;_ > allout-hide-region-body (start end)
3770 (defun allout-hide-region-body (start end
)
3771 "Hide all body lines in the region, but not headings."
3774 (narrow-to-region start end
)
3775 (goto-char (point-min))
3777 (allout-flag-region (point)
3778 (progn (allout-pre-next-preface) (point)) ?
\r)
3781 (if (looking-at "[\n\r][\n\r]")
3784 ;;;_ > allout-expose-topic (spec)
3785 (defun allout-expose-topic (spec)
3786 "Apply exposure specs to successive outline topic items.
3788 Use the more convenient frontend, `allout-new-exposure', if you don't
3789 need evaluation of the arguments, or even better, the `allout-layout'
3790 variable-keyed mode-activation/auto-exposure feature of allout outline
3791 mode. See the respective documentation strings for more details.
3793 Cursor is left at start position.
3795 SPEC is either a number or a list.
3797 Successive specs on a list are applied to successive sibling topics.
3799 A simple spec \(either a number, one of a few symbols, or the null
3800 list) dictates the exposure for the corresponding topic.
3802 Non-null lists recursively designate exposure specs for respective
3803 subtopics of the current topic.
3805 The `:' repeat spec is used to specify exposure for any number of
3806 successive siblings, up to the trailing ones for which there are
3807 explicit specs following the `:'.
3809 Simple (numeric and null-list) specs are interpreted as follows:
3811 Numbers indicate the relative depth to open the corresponding topic.
3812 - negative numbers force the topic to be closed before opening to the
3813 absolute value of the number, so all siblings are open only to
3815 - positive numbers open to the relative depth indicated by the
3816 number, but do not force already opened subtopics to be closed.
3817 - 0 means to close topic - hide all offspring.
3819 apply prior element to all siblings at current level, *up to*
3820 those siblings that would be covered by specs following the `:'
3821 on the list. Ie, apply to all topics at level but the last
3822 ones. \(Only first of multiple colons at same level is
3823 respected - subsequent ones are discarded.)
3824 * - completely opens the topic, including bodies.
3825 + - shows all the sub headers, but not the bodies
3826 - - exposes the body of the corresponding topic.
3829 \(allout-expose-topic '(-1 : 0))
3830 Close this and all following topics at current level, exposing
3831 only their immediate children, but close down the last topic
3832 at this current level completely.
3833 \(allout-expose-topic '(-1 () : 1 0))
3834 Close current topic so only the immediate subtopics are shown;
3835 show the children in the second to last topic, and completely
3837 \(allout-expose-topic '(-2 : -1 *))
3838 Expose children and grandchildren of all topics at current
3839 level except the last two; expose children of the second to
3840 last and completely open the last one."
3842 (interactive "xExposure spec: ")
3843 (if (not (listp spec
))
3845 (let ((depth (allout-depth))
3852 (setq prev-elem curr-elem
3853 curr-elem
(car spec
)
3855 (cond ; Do current element:
3856 ((null curr-elem
) nil
)
3857 ((symbolp curr-elem
)
3858 (cond ((eq curr-elem
'*) (allout-show-current-subtree)
3859 (if (> allout-recent-end-of-subtree max-pos
)
3860 (setq max-pos allout-recent-end-of-subtree
)))
3861 ((eq curr-elem
'+) (allout-show-current-branches)
3862 (if (> allout-recent-end-of-subtree max-pos
)
3863 (setq max-pos allout-recent-end-of-subtree
)))
3864 ((eq curr-elem
'-
) (allout-show-current-entry))
3867 ;; Expand the `repeat' spec to an explicit version,
3868 ;; w.r.t. remaining siblings:
3869 (let ((residue ; = # of sibs not covered by remaining spec
3870 ;; Dang - could be nice to make use of the chart, sigh:
3871 (- (length (allout-chart-siblings))
3874 ;; Some residue - cover it with prev-elem:
3875 (setq spec
(append (make-list residue prev-elem
)
3877 ((numberp curr-elem
)
3878 (if (and (>= 0 curr-elem
) (allout-visible-p))
3879 (save-excursion (allout-hide-current-subtree t
)
3882 (if (> allout-recent-end-of-subtree max-pos
)
3884 allout-recent-end-of-subtree
)))))
3885 (if (> (abs curr-elem
) 0)
3886 (progn (allout-show-children (abs curr-elem
))
3887 (if (> allout-recent-end-of-subtree max-pos
)
3888 (setq max-pos allout-recent-end-of-subtree
)))))
3890 (if (allout-descend-to-depth (1+ depth
))
3891 (let ((got (allout-expose-topic curr-elem
)))
3892 (if (and got
(> got max-pos
)) (setq max-pos got
))))))
3893 (cond (stay (setq stay nil
))
3894 ((listp (car spec
)) nil
)
3895 ((> max-pos
(point))
3896 ;; Capitalize on max-pos state to get us nearer next sibling:
3897 (progn (goto-char (min (point-max) max-pos
))
3898 (allout-next-heading)))
3899 ((allout-next-sibling depth
))))
3901 ;;;_ > allout-old-expose-topic (spec &rest followers)
3902 (defun allout-old-expose-topic (spec &rest followers
)
3904 "Deprecated. Use `allout-expose-topic' \(with different schema
3907 Dictate wholesale exposure scheme for current topic, according to SPEC.
3909 SPEC is either a number or a list. Optional successive args
3910 dictate exposure for subsequent siblings of current topic.
3912 A simple spec (either a number, a special symbol, or the null list)
3913 dictates the overall exposure for a topic. Non null lists are
3914 composite specs whose first element dictates the overall exposure for
3915 a topic, with the subsequent elements in the list interpreted as specs
3916 that dictate the exposure for the successive offspring of the topic.
3918 Simple (numeric and null-list) specs are interpreted as follows:
3920 - Numbers indicate the relative depth to open the corresponding topic:
3921 - negative numbers force the topic to be close before opening to the
3922 absolute value of the number.
3923 - positive numbers just open to the relative depth indicated by the number.
3925 - `*' completely opens the topic, including bodies.
3926 - `+' shows all the sub headers, but not the bodies
3927 - `-' exposes the body and immediate offspring of the corresponding topic.
3929 If the spec is a list, the first element must be a number, which
3930 dictates the exposure depth of the topic as a whole. Subsequent
3931 elements of the list are nested SPECs, dictating the specific exposure
3932 for the corresponding offspring of the topic.
3934 Optional FOLLOWER arguments dictate exposure for succeeding siblings."
3936 (interactive "xExposure spec: ")
3937 (let ((depth (allout-current-depth))
3940 (cond ((null spec
) nil
)
3942 (if (eq spec
'*) (allout-show-current-subtree))
3943 (if (eq spec
'+) (allout-show-current-branches))
3944 (if (eq spec
'-
) (allout-show-current-entry)))
3947 (save-excursion (allout-hide-current-subtree t
)
3949 (if (or (not max-pos
)
3950 (> (point) max-pos
))
3951 (setq max-pos
(point)))
3953 (setq spec
(* -
1 spec
)))))
3955 (allout-show-children spec
)))
3957 ;(let ((got (allout-old-expose-topic (car spec))))
3958 ; (if (and got (or (not max-pos) (> got max-pos)))
3959 ; (setq max-pos got)))
3960 (let ((new-depth (+ (allout-current-depth) 1))
3962 (setq max-pos
(allout-old-expose-topic (car spec
)))
3963 (setq spec
(cdr spec
))
3965 (allout-descend-to-depth new-depth
)
3966 (not (allout-hidden-p)))
3967 (progn (setq got
(apply 'allout-old-expose-topic spec
))
3968 (if (and got
(or (not max-pos
) (> got max-pos
)))
3969 (setq max-pos got
)))))))
3970 (while (and followers
3971 (progn (if (and max-pos
(< (point) max-pos
))
3972 (progn (goto-char max-pos
)
3973 (setq max-pos nil
)))
3975 (allout-next-sibling depth
)))
3976 (allout-old-expose-topic (car followers
))
3977 (setq followers
(cdr followers
)))
3979 ;;;_ > allout-new-exposure '()
3980 (defmacro allout-new-exposure
(&rest spec
)
3981 "Literal frontend for `allout-expose-topic', doesn't evaluate arguments.
3982 Some arguments that would need to be quoted in `allout-expose-topic'
3983 need not be quoted in `allout-new-exposure'.
3985 Cursor is left at start position.
3987 Use this instead of obsolete `allout-exposure'.
3990 \(allout-exposure (-1 () () () 1) 0)
3991 Close current topic at current level so only the immediate
3992 subtopics are shown, except also show the children of the
3993 third subtopic; and close the next topic at the current level.
3994 \(allout-exposure : -1 0)
3995 Close all topics at current level to expose only their
3996 immediate children, except for the last topic at the current
3997 level, in which even its immediate children are hidden.
3998 \(allout-exposure -2 : -1 *)
3999 Expose children and grandchildren of first topic at current
4000 level, and expose children of subsequent topics at current
4001 level *except* for the last, which should be opened completely."
4002 (list 'save-excursion
4003 '(if (not (or (allout-goto-prefix)
4004 (allout-next-heading)))
4005 (error "allout-new-exposure: Can't find any outline topics"))
4006 (list 'allout-expose-topic
(list 'quote spec
))))
4007 ;;;_ > allout-exposure '()
4008 (defmacro allout-exposure
(&rest spec
)
4009 "Being deprecated - use more recent `allout-new-exposure' instead.
4011 Literal frontend for `allout-old-expose-topic', doesn't evaluate arguments
4012 and retains start position."
4013 (list 'save-excursion
4014 '(if (not (or (allout-goto-prefix)
4015 (allout-next-heading)))
4016 (error "Can't find any outline topics"))
4017 (cons 'allout-old-expose-topic
4018 (mapcar (function (lambda (x) (list 'quote x
))) spec
))))
4020 ;;;_ #7 Systematic outline presentation - copying, printing, flattening
4022 ;;;_ - Mapping and processing of topics
4023 ;;;_ ( See also Subtree Charting, in Navigation code.)
4024 ;;;_ > allout-stringify-flat-index (flat-index)
4025 (defun allout-stringify-flat-index (flat-index &optional context
)
4026 "Convert list representing section/subsection/... to document string.
4028 Optional arg CONTEXT indicates interior levels to include."
4032 (context-depth (or (and context
2) 1)))
4033 ;; Take care of the explicit context:
4034 (while (> context-depth
0)
4035 (setq numstr
(int-to-string (car flat-index
))
4036 flat-index
(cdr flat-index
)
4037 result
(if flat-index
4038 (cons delim
(cons numstr result
))
4039 (cons numstr result
))
4040 context-depth
(if flat-index
(1- context-depth
) 0)))
4042 ;; Take care of the indentation:
4049 (1+ (truncate (if (zerop (car flat-index
))
4051 (log10 (car flat-index
)))))
4054 (setq flat-index
(cdr flat-index
)))
4055 ;; Dispose of single extra delim:
4056 (setq result
(cdr result
))))
4057 (apply 'concat result
)))
4058 ;;;_ > allout-stringify-flat-index-plain (flat-index)
4059 (defun allout-stringify-flat-index-plain (flat-index)
4060 "Convert list representing section/subsection/... to document string."
4064 (setq result
(cons (int-to-string (car flat-index
))
4066 (cons delim result
))))
4067 (setq flat-index
(cdr flat-index
)))
4068 (apply 'concat result
)))
4069 ;;;_ > allout-stringify-flat-index-indented (flat-index)
4070 (defun allout-stringify-flat-index-indented (flat-index)
4071 "Convert list representing section/subsection/... to document string."
4075 ;; Take care of the explicit context:
4076 (setq numstr
(int-to-string (car flat-index
))
4077 flat-index
(cdr flat-index
)
4078 result
(if flat-index
4079 (cons delim
(cons numstr result
))
4080 (cons numstr result
)))
4082 ;; Take care of the indentation:
4089 (1+ (truncate (if (zerop (car flat-index
))
4091 (log10 (car flat-index
)))))
4094 (setq flat-index
(cdr flat-index
)))
4095 ;; Dispose of single extra delim:
4096 (setq result
(cdr result
))))
4097 (apply 'concat result
)))
4098 ;;;_ > allout-listify-exposed (&optional start end format)
4099 (defun allout-listify-exposed (&optional start end format
)
4101 "Produce a list representing exposed topics in current region.
4103 This list can then be used by `allout-process-exposed' to manipulate
4106 Optional START and END indicate bounds of region.
4108 optional arg, FORMAT, designates an alternate presentation form for
4111 list - Present prefix as numeric section.subsection..., starting with
4112 section indicated by the list, innermost nesting first.
4113 `indent' \(symbol) - Convert header prefixes to all white space,
4114 except for distinctive bullets.
4116 The elements of the list produced are lists that represents a topic
4117 header and body. The elements of that list are:
4119 - a number representing the depth of the topic,
4120 - a string representing the header-prefix, including trailing whitespace and
4122 - a string representing the bullet character,
4123 - and a series of strings, each containing one line of the exposed
4124 portion of the topic entry."
4130 (strings prefix pad result depth new-depth out gone-out bullet beg
4135 ;; Goto initial topic, and register preceeding stuff, if any:
4136 (if (> (allout-goto-prefix) start
)
4137 ;; First topic follows beginning point - register preliminary stuff:
4138 (setq result
(list (list 0 "" nil
4139 (buffer-substring start
(1- (point)))))))
4140 (while (and (not done
)
4141 (not (eobp)) ; Loop until we've covered the region.
4142 (not (> (point) end
)))
4143 (setq depth
(allout-recent-depth) ; Current topics depth,
4144 bullet
(allout-recent-bullet) ; ... bullet,
4145 prefix
(allout-recent-prefix)
4146 beg
(progn (allout-end-of-prefix t
) (point))) ; and beginning.
4147 (setq done
; The boundary for the current topic:
4148 (not (allout-next-visible-heading 1)))
4149 (setq new-depth
(allout-recent-depth))
4151 out
(< new-depth depth
))
4156 (while (> next
(point)) ; Get all the exposed text in
4158 (cons (buffer-substring
4160 ;To hidden text or end of line:
4162 (search-forward "\r"
4163 (save-excursion (end-of-line)
4166 (if (= (preceding-char) ?
\r)
4170 (if (< (point) next
) ; Resume from after hid text, if any.
4173 ;; Accumulate list for this topic:
4174 (setq strings
(nreverse strings
))
4178 (let ((special (if (string-match
4179 (regexp-quote bullet
)
4180 allout-distinctive-bullets-string
)
4182 (cond ((listp format
)
4184 (if allout-abbreviate-flattened-numbering
4185 (allout-stringify-flat-index format
4187 (allout-stringify-flat-index-plain
4191 ((eq format
'indent
)
4194 (concat (make-string (1+ depth
) ?
)
4195 (substring prefix -
1))
4198 (make-string depth ?
)
4200 (t (error "allout-listify-exposed: %s %s"
4201 "invalid format" format
))))
4202 (list depth prefix strings
))
4204 ;; Reasses format, if any:
4205 (if (and format
(listp format
))
4206 (cond ((= new-depth depth
)
4207 (setq format
(cons (1+ (car format
))
4209 ((> new-depth depth
) ; descending - assume by 1:
4210 (setq format
(cons 1 format
)))
4213 (while (< new-depth depth
)
4214 (setq format
(cdr format
))
4215 (setq depth
(1- depth
)))
4216 ; And increment the current one:
4218 (cons (1+ (or (car format
)
4221 ;; Put the list with first at front, to last at back:
4222 (nreverse result
))))
4223 ;;;_ > allout-process-exposed (&optional func from to frombuf
4225 (defun allout-process-exposed (&optional func from to frombuf tobuf
4226 format
&optional start-num
)
4227 "Map function on exposed parts of current topic; results to another buffer.
4229 All args are options; default values itemized below.
4231 Apply FUNCTION to exposed portions FROM position TO position in buffer
4232 FROMBUF to buffer TOBUF. Sixth optional arg, FORMAT, designates an
4233 alternate presentation form:
4235 `flat' - Present prefix as numeric section.subsection..., starting with
4236 section indicated by the start-num, innermost nesting first.
4237 X`flat-indented' - Prefix is like `flat' for first topic at each
4238 X level, but subsequent topics have only leaf topic
4239 X number, padded with blanks to line up with first.
4240 `indent' \(symbol) - Convert header prefixes to all white space,
4241 except for distinctive bullets.
4244 FUNCTION: `allout-insert-listified'
4245 FROM: region start, if region active, else start of buffer
4246 TO: region end, if region active, else end of buffer
4247 FROMBUF: current buffer
4248 TOBUF: buffer name derived: \"*current-buffer-name exposed*\"
4251 ; Resolve arguments,
4252 ; defaulting if necessary:
4253 (if (not func
) (setq func
'allout-insert-listified
))
4254 (if (not (and from to
))
4255 (if (my-region-active-p)
4256 (setq from
(region-beginning) to
(region-end))
4257 (setq from
(point-min) to
(point-max))))
4259 (if (not (bufferp frombuf
))
4260 ;; Specified but not a buffer - get it:
4261 (let ((got (get-buffer frombuf
)))
4263 (error (concat "allout-process-exposed: source buffer "
4266 (setq frombuf got
))))
4267 ;; not specified - default it:
4268 (setq frombuf
(current-buffer)))
4270 (if (not (bufferp tobuf
))
4271 (setq tobuf
(get-buffer-create tobuf
)))
4272 ;; not specified - default it:
4273 (setq tobuf
(concat "*" (buffer-name frombuf
) " exposed*")))
4278 (progn (set-buffer frombuf
)
4279 (allout-listify-exposed from to format
))))
4281 (mapcar func listified
)
4282 (pop-to-buffer tobuf
)))
4285 ;;;_ > allout-insert-listified (listified)
4286 (defun allout-insert-listified (listified)
4287 "Insert contents of listified outline portion in current buffer.
4289 Listified is a list representing each topic header and body:
4291 \`(depth prefix text)'
4293 or \`(depth prefix text bullet-plus)'
4295 If `bullet-plus' is specified, it is inserted just after the entire prefix."
4296 (setq listified
(cdr listified
))
4297 (let ((prefix (prog1
4299 (setq listified
(cdr listified
))))
4302 (setq listified
(cdr listified
))))
4303 (bullet-plus (car listified
)))
4305 (if bullet-plus
(insert (concat " " bullet-plus
)))
4308 (if (setq text
(cdr text
))
4311 ;;;_ > allout-copy-exposed-to-buffer (&optional arg tobuf format)
4312 (defun allout-copy-exposed-to-buffer (&optional arg tobuf format
)
4313 "Duplicate exposed portions of current outline to another buffer.
4315 Other buffer has current buffers name with \" exposed\" appended to it.
4317 With repeat count, copy the exposed parts of only the current topic.
4319 Optional second arg TOBUF is target buffer name.
4321 Optional third arg FORMAT, if non-nil, symbolically designates an
4322 alternate presentation format for the outline:
4324 `flat' - Convert topic header prefixes to numeric
4325 section.subsection... identifiers.
4326 `indent' - Convert header prefixes to all white space, except for
4327 distinctive bullets.
4328 `indent-flat' - The best of both - only the first of each level has
4329 the full path, the rest have only the section number
4330 of the leaf, preceded by the right amount of indentation."
4334 (setq tobuf
(get-buffer-create (concat "*" (buffer-name) " exposed*"))))
4335 (let* ((start-pt (point))
4336 (beg (if arg
(allout-back-to-current-heading) (point-min)))
4337 (end (if arg
(allout-end-of-current-subtree) (point-max)))
4338 (buf (current-buffer))
4340 (if (eq format
'flat
)
4341 (setq format
(if arg
(save-excursion
4343 (allout-topic-flat-index))
4345 (save-excursion (set-buffer tobuf
)(erase-buffer))
4346 (allout-process-exposed 'allout-insert-listified
4352 (goto-char (point-min))
4354 (goto-char start-pt
)))
4355 ;;;_ > allout-flatten-exposed-to-buffer (&optional arg tobuf)
4356 (defun allout-flatten-exposed-to-buffer (&optional arg tobuf
)
4357 "Present numeric outline of outline's exposed portions in another buffer.
4359 The resulting outline is not compatable with outline mode - use
4360 `allout-copy-exposed-to-buffer' if you want that.
4362 Use `allout-indented-exposed-to-buffer' for indented presentation.
4364 With repeat count, copy the exposed portions of only current topic.
4366 Other buffer has current buffers name with \" exposed\" appended to
4367 it, unless optional second arg TOBUF is specified, in which case it is
4370 (allout-copy-exposed-to-buffer arg tobuf
'flat
))
4371 ;;;_ > allout-indented-exposed-to-buffer (&optional arg tobuf)
4372 (defun allout-indented-exposed-to-buffer (&optional arg tobuf
)
4373 "Present indented outline of outline's exposed portions in another buffer.
4375 The resulting outline is not compatable with outline mode - use
4376 `allout-copy-exposed-to-buffer' if you want that.
4378 Use `allout-flatten-exposed-to-buffer' for numeric sectional presentation.
4380 With repeat count, copy the exposed portions of only current topic.
4382 Other buffer has current buffers name with \" exposed\" appended to
4383 it, unless optional second arg TOBUF is specified, in which case it is
4386 (allout-copy-exposed-to-buffer arg tobuf
'indent
))
4388 ;;;_ - LaTeX formatting
4389 ;;;_ > allout-latex-verb-quote (str &optional flow)
4390 (defun allout-latex-verb-quote (str &optional flow
)
4391 "Return copy of STRING for literal reproduction across latex processing.
4392 Expresses the original characters \(including carriage returns) of the
4393 string across latex processing."
4394 (mapconcat (function
4396 (cond ((memq char
'(?
\\ ?$ ?% ?
# ?
& ?
{ ?
} ?_ ?^ ?- ?
*))
4397 (concat "\\char" (number-to-string char
) "{}"))
4398 ((= char ?
\n) "\\\\")
4399 (t (char-to-string char
)))))
4402 ;;;_ > allout-latex-verbatim-quote-curr-line ()
4403 (defun allout-latex-verbatim-quote-curr-line ()
4404 "Express line for exact \(literal) representation across latex processing.
4406 Adjust line contents so it is unaltered \(from the original line)
4407 across latex processing, within the context of a `verbatim'
4408 environment. Leaves point at the end of the line."
4411 (end (progn (end-of-line)(point))))
4413 (while (re-search-forward "\\\\"
4414 ;;"\\\\\\|\\{\\|\\}\\|\\_\\|\\$\\|\\\"\\|\\&\\|\\^\\|\\-\\|\\*\\|#"
4415 end
; bounded by end-of-line
4416 1) ; no matches, move to end & return nil
4417 (goto-char (match-beginning 0))
4420 (goto-char (1+ (match-end 0))))))
4421 ;;;_ > allout-insert-latex-header (buf)
4422 (defun allout-insert-latex-header (buf)
4423 "Insert initial latex commands at point in BUFFER."
4424 ;; Much of this is being derived from the stuff in appendix of E in
4425 ;; the TeXBook, pg 421.
4427 (let ((doc-style (format "\n\\documentstyle{%s}\n"
4429 (page-numbering (if allout-number-pages
4430 "\\pagestyle{empty}\n"
4432 (linesdef (concat "\\def\\beginlines{"
4433 "\\par\\begingroup\\nobreak\\medskip"
4435 " \\kern1pt\\nobreak \\obeylines \\obeyspaces "
4436 "\\everypar{\\strut}}\n"
4438 "\\kern1pt\\endgroup\\medbreak\\noindent}\n"))
4439 (titlecmd (format "\\newcommand{\\titlecmd}[1]{{%s #1}}\n"
4440 allout-title-style
))
4441 (labelcmd (format "\\newcommand{\\labelcmd}[1]{{%s #1}}\n"
4442 allout-label-style
))
4443 (headlinecmd (format "\\newcommand{\\headlinecmd}[1]{{%s #1}}\n"
4444 allout-head-line-style
))
4445 (bodylinecmd (format "\\newcommand{\\bodylinecmd}[1]{{%s #1}}\n"
4446 allout-body-line-style
))
4447 (setlength (format "%s%s%s%s"
4448 "\\newlength{\\stepsize}\n"
4449 "\\setlength{\\stepsize}{"
4452 (oneheadline (format "%s%s%s%s%s%s%s"
4453 "\\newcommand{\\OneHeadLine}[3]{%\n"
4455 "\\hspace*{#2\\stepsize}%\n"
4456 "\\labelcmd{#1}\\hspace*{.2cm}"
4457 "\\headlinecmd{#3}\\\\["
4460 (onebodyline (format "%s%s%s%s%s%s"
4461 "\\newcommand{\\OneBodyLine}[2]{%\n"
4463 "\\hspace*{#1\\stepsize}%\n"
4464 "\\bodylinecmd{#2}\\\\["
4467 (begindoc "\\begin{document}\n\\begin{center}\n")
4468 (title (format "%s%s%s%s"
4470 (allout-latex-verb-quote (if allout-title
4473 ('error
"<unnamed buffer>"))
4476 "\\end{center}\n\n"))
4477 (hsize "\\hsize = 7.5 true in\n")
4478 (hoffset "\\hoffset = -1.5 true in\n")
4479 (vspace "\\vspace{.1cm}\n\n"))
4480 (insert (concat doc-style
4495 ;;;_ > allout-insert-latex-trailer (buf)
4496 (defun allout-insert-latex-trailer (buf)
4497 "Insert concluding latex commands at point in BUFFER."
4499 (insert "\n\\end{document}\n"))
4500 ;;;_ > allout-latexify-one-item (depth prefix bullet text)
4501 (defun allout-latexify-one-item (depth prefix bullet text
)
4502 "Insert LaTeX commands for formatting one outline item.
4504 Args are the topics numeric DEPTH, the header PREFIX lead string, the
4505 BULLET string, and a list of TEXT strings for the body."
4506 (let* ((head-line (if text
(car text
)))
4507 (body-lines (cdr text
))
4511 (insert (concat "\\OneHeadLine{\\verb\1 "
4512 (allout-latex-verb-quote bullet
)
4517 (allout-latex-verb-quote head-line
)
4520 (if (not body-lines
)
4522 ;;(insert "\\beginlines\n")
4523 (insert "\\begin{verbatim}\n")
4525 (setq curr-line
(car body-lines
))
4526 (if (and (not body-content
)
4527 (not (string-match "^\\s-*$" curr-line
)))
4528 (setq body-content t
))
4529 ; Mangle any occurrences of
4530 ; "\end{verbatim}" in text,
4532 (if (and body-content
4533 (setq bop
(string-match "\\end{verbatim}" curr-line
)))
4534 (setq curr-line
(concat (substring curr-line
0 bop
)
4536 (substring curr-line bop
))))
4537 ;;(insert "|" (car body-lines) "|")
4539 (allout-latex-verbatim-quote-curr-line)
4541 (setq body-lines
(cdr body-lines
)))
4543 (setq body-content nil
)
4547 ;;(insert "\\endlines\n")
4548 (insert "\\end{verbatim}\n")
4550 ;;;_ > allout-latexify-exposed (arg &optional tobuf)
4551 (defun allout-latexify-exposed (arg &optional tobuf
)
4552 "Format current topics exposed portions to TOBUF for latex processing.
4553 TOBUF defaults to a buffer named the same as the current buffer, but
4554 with \"*\" prepended and \" latex-formed*\" appended.
4556 With repeat count, copy the exposed portions of entire buffer."
4561 (get-buffer-create (concat "*" (buffer-name) " latexified*"))))
4562 (let* ((start-pt (point))
4563 (beg (if arg
(point-min) (allout-back-to-current-heading)))
4564 (end (if arg
(point-max) (allout-end-of-current-subtree)))
4565 (buf (current-buffer)))
4568 (allout-insert-latex-header tobuf
)
4569 (goto-char (point-max))
4570 (allout-process-exposed 'allout-latexify-one-item
4575 (goto-char (point-max))
4576 (allout-insert-latex-trailer tobuf
)
4577 (goto-char (point-min))
4579 (goto-char start-pt
)))
4581 ;;;_ #8 miscellaneous
4582 ;;;_ > allout-mark-topic ()
4583 (defun allout-mark-topic ()
4584 "Put the region around topic currently containing point."
4587 (allout-goto-prefix)
4589 (allout-end-of-current-subtree)
4590 (exchange-point-and-mark))
4591 ;;;_ > outlineify-sticky ()
4592 ;; outlinify-sticky is correct spelling; provide this alias for sticklers:
4593 (defalias 'outlinify-sticky
'outlineify-sticky
)
4594 (defun outlineify-sticky (&optional arg
)
4595 "Activate outline mode and establish file var so it is started subsequently.
4597 See doc-string for `allout-layout' and `allout-init' for details on
4598 setup for auto-startup."
4605 (goto-char (point-min))
4606 (if (looking-at allout-regexp
)
4608 (allout-open-topic 2)
4609 (insert (concat "Dummy outline topic header - see"
4610 "`allout-mode' docstring: `^Hm'."))
4612 (goto-char (point-max))
4614 (allout-open-topic 0)
4615 (insert "Local emacs vars.\n")
4616 (allout-open-topic 1)
4617 (insert "(`allout-layout' is for allout.el allout-mode)\n")
4618 (allout-open-topic 0)
4619 (insert "Local variables:\n")
4620 (allout-open-topic 0)
4621 (insert (format "allout-layout: %s\n"
4624 (allout-open-topic 0)
4625 (insert "End:\n"))))
4626 ;;;_ > solicit-char-in-string (prompt string &optional do-defaulting)
4627 (defun solicit-char-in-string (prompt string
&optional do-defaulting
)
4628 "Solicit (with first arg PROMPT) choice of a character from string STRING.
4630 Optional arg DO-DEFAULTING indicates to accept empty input (CR)."
4632 (let ((new-prompt prompt
)
4636 (message "%s" new-prompt
)
4638 ;; We do our own reading here, so we can circumvent, eg, special
4639 ;; treatment for `?' character. (Oughta use minibuffer keymap instead.)
4641 (char-to-string (let ((cursor-in-echo-area nil
)) (read-char))))
4644 (cond ((string-match (regexp-quote got
) string
) got
)
4645 ((and do-defaulting
(string= got
"\r"))
4646 ;; Return empty string to default:
4648 ((string= got
"\C-g") (signal 'quit nil
))
4650 (setq new-prompt
(concat prompt
4656 ;; got something out of loop - return it:
4659 ;;;_ > regexp-sans-escapes (string)
4660 (defun regexp-sans-escapes (regexp &optional successive-backslashes
)
4661 "Return a copy of REGEXP with all character escapes stripped out.
4663 Representations of actual backslashes - '\\\\\\\\' - are left as a
4666 Optional arg SUCCESSIVE-BACKSLASHES is used internally for recursion."
4668 (if (string= regexp
"")
4670 ;; Set successive-backslashes to number if current char is
4671 ;; backslash, or else to nil:
4672 (setq successive-backslashes
4673 (if (= (aref regexp
0) ?
\\)
4674 (if successive-backslashes
(1+ successive-backslashes
) 1)
4676 (if (or (not successive-backslashes
) (= 2 successive-backslashes
))
4677 ;; Include first char:
4678 (concat (substring regexp
0 1)
4679 (regexp-sans-escapes (substring regexp
1)))
4680 ;; Exclude first char, but maintain count:
4681 (regexp-sans-escapes (substring regexp
1) successive-backslashes
))))
4682 ;;;_ > my-region-active-p ()
4683 (defmacro my-region-active-p
()
4684 (if (fboundp 'region-active-p
)
4687 ;;;_ - add-hook definition for divergent emacsen
4688 ;;;_ > add-hook (hook function &optional append)
4689 (if (not (fboundp 'add-hook
))
4690 (defun add-hook (hook function
&optional append
)
4691 "Add to the value of HOOK the function FUNCTION unless already present.
4692 \(It becomes the first hook on the list unless optional APPEND is non-nil, in
4693 which case it becomes the last). HOOK should be a symbol, and FUNCTION may be
4694 any valid function. HOOK's value should be a list of functions, not a single
4695 function. If HOOK is void, it is first set to nil."
4696 (or (boundp hook
) (set hook nil
))
4697 (or (if (consp function
)
4698 ;; Clever way to tell whether a given lambda-expression
4699 ;; is equal to anything in the hook.
4700 (let ((tail (assoc (cdr function
) (symbol-value hook
))))
4701 (equal function tail
))
4702 (memq function
(symbol-value hook
)))
4705 (nconc (symbol-value hook
) (list function
))
4706 (cons function
(symbol-value hook
)))))))
4707 ;;;_ : my-mark-marker to accommodate divergent emacsen:
4708 (defun my-mark-marker (&optional force buffer
)
4709 "Accommodate the different signature for mark-marker across emacsen.
4711 GNU XEmacs takes two optional args, while mainline GNU Emacs does not,
4712 so pass them along when appropriate."
4713 (if (featurep 'xemacs
)
4714 (mark-marker force buffer
)
4717 ;;;_ #9 Under development
4718 ;;;_ > allout-bullet-isearch (&optional bullet)
4719 (defun allout-bullet-isearch (&optional bullet
)
4720 "Isearch \(regexp) for topic with bullet BULLET."
4723 (setq bullet
(solicit-char-in-string
4724 "ISearch for topic with bullet: "
4725 (regexp-sans-escapes allout-bullets-string
))))
4727 (let ((isearch-regexp t
)
4728 (isearch-string (concat "^"
4729 allout-header-prefix
4732 (isearch-repeat 'forward
)
4734 ;;;_ ? Re hooking up with isearch - use isearch-op-fun rather than
4735 ;;; wrapping the isearch functions.
4737 ;;;_* Local emacs vars.
4738 ;;; The following `allout-layout' local variable setting:
4739 ;;; - closes all topics from the first topic to just before the third-to-last,
4740 ;;; - shows the children of the third to last (config vars)
4741 ;;; - and the second to last (code section),
4742 ;;; - and closes the last topic (this local-variables section).
4744 ;;;allout-layout: (0 : -1 -1 0)
4747 ;;; arch-tag: cf38fbc3-c044-450f-8bff-afed8ba5681c
4748 ;;; allout.el ends here