(set-visited-file-name, file-expand-wildcards): Fix docstring.
[emacs.git] / lisp / allout.el
blobb2cc486df6ad6ed5238de82299d2200914f81ae6
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)
15 ;; any later version.
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.
27 ;;; Commentary:
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
62 ;;; Code:
64 ;;;_* Provide
65 (provide 'allout)
67 ;;;_* USER CUSTOMIZATION VARIABLES:
68 (defgroup allout nil
69 "Extensive outline mode for use alone and with other modes."
70 :prefix "allout-"
71 :group 'editing)
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,
92 auto-layout is not.
94 With value nil, neither auto-mode-activation nor auto-layout are
95 enabled.
97 See the docstring for `allout-init' for the proper interface to
98 this variable."
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))
103 :group 'allout)
104 ;;;_ = allout-layout
105 (defvar allout-layout nil
106 "*Layout specification and provisional mode trigger for allout outlines.
108 Buffer-specific.
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:
123 ;;;Local variables:
124 ;;;allout-layout: \(0 : -1 -1 0)
125 ;;;End:
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
139 just the header."
140 :type 'boolean
141 :group 'allout)
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."
153 :type 'string
154 :group 'allout)
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
167 bullets."
168 :type 'string
169 :group 'allout)
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
176 bullets.
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."
182 :type 'string
183 :group 'allout)
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:
196 `?' question topics
197 `\(' parenthetic comment \(with a matching close paren inside)
198 `[' meta-note \(with a matching close ] inside)
199 `\"' a quote
200 `=' value settings
201 `~' \"more or less\"
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
207 alternating bullets.
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
213 strings."
214 :type 'string
215 :group 'allout)
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
243 incorrect.]"
244 :type '(choice (const t) (const nil) string
245 (const allout-mode-leaders)
246 (const comment-start))
247 :group 'allout)
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."
270 :type 'boolean
271 :group 'allout)
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
283 prefixes:
285 * Top level
286 .* A topic
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
292 . #2 Another
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):
299 * Top level
300 .* A topic
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
306 . #2 Another
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'
315 is non-nil."
316 :type 'boolean
317 :group 'allout)
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)
329 :group 'allout)
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)
337 :group 'allout)
339 ;;;_ = allout-presentation-padding
340 (defcustom allout-presentation-padding 2
341 "*Presentation-format white-space padding factor, for greater indent."
342 :type 'integer
343 :group 'allout)
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."
352 :type 'boolean
353 :group 'allout)
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."
359 :type 'boolean
360 :group 'allout)
361 ;;;_ - allout-label-style
362 (defcustom allout-label-style "\\large\\bf"
363 "*Font and size of labels for LaTeX formatting of an outline."
364 :type 'string
365 :group 'allout)
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."
369 :type 'string
370 :group 'allout)
371 ;;;_ - allout-body-line-style
372 (defcustom allout-body-line-style " "
373 "*Font and size of entries for LaTeX formatting of an outline."
374 :type 'string
375 :group 'allout)
376 ;;;_ - allout-title-style
377 (defcustom allout-title-style "\\Large\\bf"
378 "*Font and size of titles for LaTeX formatting of an outline."
379 :type 'string
380 :group 'allout)
381 ;;;_ - allout-title
382 (defcustom allout-title '(or buffer-file-name (current-buffer-name))
383 "*Expression to be evaluated to determine the title for LaTeX
384 formatted copy."
385 :type 'sexp
386 :group 'allout)
387 ;;;_ - allout-line-skip
388 (defcustom allout-line-skip ".05cm"
389 "*Space between lines for LaTeX formatting of an outline."
390 :type 'string
391 :group 'allout)
392 ;;;_ - allout-indent
393 (defcustom allout-indent ".3cm"
394 "*LaTeX formatted depth-indent spacing."
395 :type 'string
396 :group 'allout)
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."
403 :type 'string
404 :group 'allout)
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
416 ; Motion commands:
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)
424 ; Exposure commands:
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."
456 :type 'boolean
457 :group 'allout)
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.\]"
469 :type 'boolean
470 :group 'allout)
471 (make-variable-buffer-local 'allout-use-hanging-indents)
473 ;;;_ = allout-reindent-bodies
474 (defcustom allout-reindent-bodies (if allout-use-hanging-indents
475 'text)
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
480 the header.
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))
486 :group 'allout)
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
500 behavior."
501 :type 'boolean
502 :group 'allout)
504 ;;;_* CODE - no user customizations below.
506 ;;;_ #1 Internal Outline Formatting and Configuration
507 ;;;_ : Version
508 ;;;_ = allout-version
509 (defvar allout-version
510 (let ((rcs-rev "$Revision: 1.48 $"))
511 (condition-case err
512 (save-match-data
513 (string-match "Revision: \\([0-9]+\\.[0-9]+\\)" rcs-rev)
514 (substring rcs-rev (match-beginning 1) (match-end 1)))
515 ('error rcs-rev)))
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."
520 (interactive "P")
521 (let ((msg (concat "Allout Outline Mode v " allout-version)))
522 (if here (insert msg))
523 (message "%s" msg)
524 msg))
525 ;;;_ : Topic header format
526 ;;;_ = allout-regexp
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)))
575 (set-allout-regexp))
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."
583 (interactive "P")
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)
589 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:
596 `comment-start'
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
607 comment-start
608 t)))
609 allout-use-mode-specific-leader
610 ;; Oops - garbled value, equate with effect of 't:
611 t)))
612 (leader
613 (cond
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))
622 comment-start
623 ;; Use comment-start, maybe tripled, and with
624 ;; underscore:
625 (concat
626 (if (string= " "
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:
633 "_")))))))
634 (if (not leader)
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
648 comment-start
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'."
658 (interactive)
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))
664 cur-string
665 cur-len
666 cur-char
667 cur-char-string
668 index
669 new-string)
670 (while strings
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
677 (cond
678 ; Single dash would denote a
679 ; sequence, repeated denotes
680 ; a dash:
681 ((eq cur-char ?-) "--")
682 ; literal close-square-bracket
683 ; doesn't work right in the
684 ; expr, exclude it:
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 "\\(\\"
695 allout-header-prefix
696 "[ \t]*["
697 allout-bullets-string
698 "]\\)\\|\\"
699 allout-primary-bullet
700 "+\\|\^l"))
701 (setq allout-line-boundary-regexp
702 (concat "\\([\n\r]\\)\\(" allout-regexp "\\)"))
703 (setq allout-bob-regexp
704 (concat "\\(\\`\\)\\(" allout-regexp "\\)"))
706 ;;;_ : Key bindings
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)))
717 (mapcar (function
718 (lambda (cell)
719 (let ((add-pref (null (cdr (cdr cell))))
720 (key-suff (list (car cell))))
721 (apply 'define-key
722 (list map
723 (apply 'concat (if add-pref
724 (append pref key-suff)
725 key-suff))
726 (car (cdr cell)))))))
727 keymap-list)
728 map))
730 ;;;_ : Menu bar
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 ()
736 (require 'easymenu)
737 (easy-menu-define allout-mode-exposure-menu
738 allout-mode-map
739 "Allout outline exposure menu."
740 '("Exposure"
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]
746 "----"
747 ["Show All" allout-show-all t]))
748 (easy-menu-define allout-mode-editing-menu
749 allout-mode-map
750 "Allout outline editing menu."
751 '("Headings"
752 ["Open Sibling" allout-open-sibtopic t]
753 ["Open Subtopic" allout-open-subtopic t]
754 ["Open Supertopic" allout-open-supertopic t]
755 "----"
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
762 allout-mode-map
763 "Allout outline navigation menu."
764 '("Navigation"
765 ["Next Visible Heading" allout-next-visible-heading t]
766 ["Previous Visible Heading"
767 allout-previous-visible-heading t]
768 "----"
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]
773 "----"
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
779 allout-mode-map
780 "Allout outlines miscellaneous bindings."
781 '("Misc"
782 ["Version" allout-version t]
783 "----"
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]
789 "----"
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
808 from the list."
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.
816 (if value
818 ;; Registering:
819 (progn
820 (if on-list
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
824 (cons (list name
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))))
831 ;; Relinquishing:
832 (if (not on-list)
834 ;; Oops, not registered - leave it be:
837 ;; Some registration:
838 ; reestablish it:
839 (setq prior-capsule (car (cdr on-list)))
840 (if prior-capsule
841 (set name (car prior-capsule)) ; Some prior value - reestablish it.
842 (makunbound name)) ; Previously unbound - demolish var.
843 ; Remove registration:
844 (let (rebuild)
845 (while allout-mode-prior-settings
846 (if (not (eq (car allout-mode-prior-settings)
847 on-list))
848 (setq rebuild
849 (cons (car allout-mode-prior-settings)
850 rebuild)))
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'
862 functions.")
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))
892 ,expr))
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
904 to track repeats.")
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)
912 nil)
914 ;;;_ #2 Mode activation
915 ;;;_ = allout-mode
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."
921 'allout-mode)
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)
928 ;;;###autoload
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:
954 \(require 'allout)
955 \(allout-init t)"
957 (interactive)
958 (if (interactive-p)
959 (progn
960 (setq mode
961 (completing-read
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 "")
969 (setq mode 'report)
970 (setq mode (intern-soft mode)))))
971 (let
972 ;; convenience aliases, for consistent ref to respective vars:
973 ((hook 'allout-find-file-hook)
974 (curr-mode 'allout-auto-activation))
976 (cond ((not mode)
977 (setq find-file-hook (delq hook find-file-hook))
978 (if (interactive-p)
979 (message "Allout outline mode auto-activation inhibited.")))
980 ((eq mode 'report)
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))
984 (allout-init nil)
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)
989 (message
990 "Outline mode auto-activation enabled.")
991 'activate)
992 ((eq mode 'report)
993 ;; Return the current mode setting:
994 (allout-init mode))
995 ((eq mode 'ask)
996 (message
997 (concat "Outline mode auto-activation and "
998 "-layout \(upon confirmation) enabled."))
999 'ask)
1000 ((message
1001 "Outline mode auto-activation and -layout enabled.")
1002 'full)))))))
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))
1011 cur)
1012 (while menus
1013 (setq cur (car menus)
1014 menus (cdr menus))
1015 (easy-menu-add cur))))
1016 ;;;_ > allout-mode (&optional toggle)
1017 ;;;_ : Defun:
1018 (defun allout-mode (&optional toggle)
1019 ;;;_ . Doc string:
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
1030 outline.)
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
1077 current topic.
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
1091 Misc commands:
1092 -------------
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
1104 format.
1105 ESC ESC (allout-init t) Setup emacs session for outline mode
1106 auto-activation.
1108 HOT-SPOT Operation
1110 Hot-spot operation provides a means for easy, single-keystroke outline
1111 navigation and exposure control.
1113 \\<allout-mode-map>
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
1124 operation.
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.
1131 Terminology
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,
1137 CURRENT topic:
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.
1143 ANCESTORS:
1144 The topics that contain a topic.
1145 PARENT: A topic's immediate ancestor. It has a depth one less than
1146 the topic.
1147 OFFSPRING:
1148 The topics contained by a topic;
1149 SUBTOPIC:
1150 An immediate offspring of a topic;
1151 CHILDREN:
1152 The immediate offspring of a topic.
1153 SIBLINGS:
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
1159 text.
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
1167 of the topic.
1168 PREFIX-LEAD:
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.
1178 PREFIX-PADDING:
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
1186 topic.
1187 ENTRY: The text contained in a topic before any offspring.
1188 BODY: Same as ENTRY.
1191 EXPOSURE:
1192 The state of a topic which determines the on-screen visibility
1193 of its offspring and contained text.
1194 CONCEALED:
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."
1202 ;;;_ . Code
1203 (interactive "P")
1205 (let* ((active (and (not (equal major-mode 'outline))
1206 (allout-mode-p)))
1207 ; Massage universal-arg `toggle' val:
1208 (toggle (and toggle
1209 (or (and (listp toggle)(car toggle))
1210 toggle)))
1211 ; Activation specifically demanded?
1212 (explicit-activation (or
1214 (and toggle
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)))
1221 do-layout
1224 ; See comments below re v19.18,.19 bug.
1225 (setq allout-v18/19-file-var-hack (car command-history))
1227 (cond
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
1233 ;; skip everything.
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.
1242 ;; Deactivation:
1243 ((and (not explicit-activation)
1244 (or active toggle))
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
1252 (progn
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)
1264 'auto-fill-hook
1265 'auto-fill-function))
1266 (allout-resumptions 'allout-former-auto-filler)
1267 (setq allout-mode nil))
1269 ;; Activation:
1270 ((not active)
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)
1280 (set-allout-regexp)
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))))
1300 ; and add them:
1301 (use-local-map (produce-allout-mode-map allout-keybindings-list
1302 (current-local-map)))
1305 ; selective-display is the
1306 ; emacs conditional exposure
1307 ; mechanism:
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)
1323 'auto-fill-hook
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)
1346 (if allout-layout
1347 (setq do-layout t))
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))
1356 ;; Reactivation:
1357 ((setq do-layout t)
1358 (allout-infer-body-reindent))
1359 ) ; cond
1361 (if (and do-layout
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'? "
1367 (buffer-name)
1368 allout-layout))
1370 (message "Skipped %s layout." (buffer-name))
1371 nil)
1372 t)))
1373 (save-excursion
1374 (message "Adjusting '%s' exposure..." (buffer-name))
1375 (goto-char 0)
1376 (allout-this-or-next-heading)
1377 (condition-case err
1378 (progn
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)))
1384 (sit-for 1)))))
1385 allout-mode
1386 ) ; let*
1387 ) ; defun
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))
1452 ;;;_ #4 Navigation
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."
1461 (save-excursion
1462 (beginning-of-line)
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."
1476 '(save-excursion
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."
1482 (interactive)
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."
1488 (save-excursion
1489 (if (allout-goto-prefix)
1490 (allout-recent-depth)
1491 (progn
1492 ;; Oops, no prefix, zero prefix data:
1493 (allout-prefix-data (point)(point))
1494 ;; ... and return 0:
1495 0))))
1496 ;;;_ > allout-current-depth ()
1497 (defmacro allout-current-depth ()
1498 "Return nesting depth of visible topic most immediately containing point."
1499 '(save-excursion
1500 (if (allout-back-to-current-heading)
1501 (max 1
1502 (- allout-recent-prefix-end
1503 allout-recent-prefix-beginning
1504 allout-header-subtraction))
1505 0)))
1506 ;;;_ > allout-get-current-prefix ()
1507 (defun allout-get-current-prefix ()
1508 "Topic prefix of the current topic."
1509 (save-excursion
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)."
1515 (save-excursion
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."
1521 (condition-case err
1522 (save-excursion
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..."
1545 (save-excursion
1546 (cond ((and depth (<= depth 0) 0))
1547 ((or (not depth) (= depth (allout-depth)))
1548 (let ((index 1))
1549 (while (allout-previous-sibling (allout-recent-depth) nil)
1550 (setq index (1+ index)))
1551 index))
1552 ((< depth (allout-recent-depth))
1553 (allout-ascend-to-depth depth)
1554 (allout-sibling-index))
1555 (0))))
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))
1562 (rev-sibls nil))
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)))
1567 rev-sibls)
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)))
1578 (forward-char 1))
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."
1597 '(if (bobp)
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:
1605 (allout-prefix-data
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
1626 use.
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
1637 itself.
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.
1644 chart curr-depth)
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)
1677 (or (not levels)
1678 (> levels 0)))
1679 ;; Recurse on deeper level of curr topic:
1680 (setq chart
1681 (cons (allout-chart-subtree (and levels
1682 (1- levels))
1683 orig-depth
1684 curr-depth)
1685 chart))
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
1695 ; to the end of it:
1696 (progn (and (not (eobp)) (forward-char -1))
1697 (and (memq (preceding-char) '(?\n ?\r))
1698 (memq (aref (buffer-substring (max 1 (- (point) 3))
1699 (point))
1701 '(?\n ?\r))
1702 (forward-char -1))
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."
1713 (save-excursion
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
1725 start point."
1727 (let (result here)
1728 (while (and (or (eq depth t) (> depth 0))
1729 chart)
1730 (setq here (car chart))
1731 (if (listp here)
1732 (let ((further (allout-chart-to-reveal here (or (eq depth t)
1733 (1- depth)))))
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)))
1738 (goto-char here)
1739 (if (= (preceding-char) ?\r)
1740 (setq result (cons here result)))
1741 (setq chart (cdr chart))))
1742 result))
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
1758 exposed reside.
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
1764 opened.
1765 - Lists signify the beginning and end points of regions that should
1766 be flagged, and the flag to employ. (For concealment: `\(\?r\)', and
1767 exposure:"
1768 (while spec
1769 (cond ((listp spec)
1772 (setq spec (cdr spec)))
1775 ;;;_ - Within Topic
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."
1786 (let (done)
1787 (while (and (not done)
1788 (re-search-backward "[\n\r]" nil 1))
1789 (forward-char 1)
1790 (if (looking-at allout-regexp)
1791 (setq done (allout-prefix-data (match-beginning 0)
1792 (match-end 0)))
1793 (forward-char -1)))
1794 (if (bobp)
1795 (cond ((looking-at allout-regexp)
1796 (allout-prefix-data (match-beginning 0)(match-end 0)))
1797 ((allout-next-heading))
1798 (done))
1799 done)))
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."
1829 (beginning-of-line)
1830 (prog1 (or (allout-on-current-heading-p)
1831 (and (re-search-backward (concat "^\\(" allout-regexp "\\)")
1833 'move)
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."
1850 (interactive)
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)
1860 '(?\n ?\r))
1861 (forward-char -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.)"
1869 (interactive)
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."
1878 (interactive)
1879 (allout-show-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 ()
1885 (interactive)
1886 (allout-beginning-of-current-entry)
1887 (forward-line -1)
1888 (end-of-line))
1889 (defalias 'allout-end-of-heading 'allout-end-of-current-heading)
1891 ;;;_ - Depth-wise
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)
1903 depth)
1904 (goto-char last-good)
1905 nil))
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."
1910 (prog1
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)))
1921 (while
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))
1928 depth
1929 (goto-char start-point)
1930 nil))
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."
1939 (interactive "p")
1940 (allout-back-to-current-heading)
1941 (let ((present-level (allout-recent-depth))
1942 (last-good (point))
1943 failed
1944 return)
1945 ;; Loop for iterating arg:
1946 (while (and (> (allout-recent-depth) 1)
1947 (> arg 0)
1948 (not (bobp))
1949 (not failed))
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)))
1957 (if (or failed
1958 (> arg 0))
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))
1964 nil))
1965 (if (interactive-p) (allout-end-of-prefix))
1966 allout-recent-prefix-beginning)))
1968 ;;;_ - Linear
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))
1983 last-depth)
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)
1994 nil))))
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))
2013 (forward-char -1))
2014 (if (or (bobp) (not (memq (preceding-char) '(?\n ?\r))))
2016 (forward-char -1)
2017 (if (or (bobp) (not (memq (preceding-char) '(?\n ?\r))))
2018 (forward-char -1)))
2019 (point))
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."
2039 (interactive "p")
2040 (let* ((backward (if (< arg 0) (setq arg (* -1 arg))))
2041 (step (if backward -1 1))
2042 (start-point (point))
2043 prev got)
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'
2065 matches)."
2066 (interactive "p")
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."
2075 (interactive "p")
2076 (let ((start-depth (allout-current-depth))
2077 (start-point (point))
2078 (start-arg arg)
2079 (backward (> 0 arg))
2080 last-depth
2081 (last-good (point))
2082 at-boundary)
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)
2087 at-boundary))
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)
2095 arg (1- arg))
2096 (setq at-boundary t)))
2097 (if (and (not (eobp))
2098 (= arg 0)
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'."
2114 (interactive "p")
2115 (if (interactive-p)
2116 (let ((current-prefix-arg (* -1 arg)))
2117 (call-interactively 'allout-forward-current-level))
2118 (allout-forward-current-level (* -1 arg))))
2120 ;;;_ #5 Alteration
2122 ;;;_ - Fundamental
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
2154 ; be exposed:
2155 (save-excursion (if (memq this-command '(newline open-line))
2156 ;; Compensate for stupid emacs {new,
2157 ;; open-}line display optimization:
2158 (setq beg (1+ beg)
2159 end (1+ end)))
2160 (goto-char beg)
2161 (or (allout-hidden-p)
2162 (and (not (= beg end))
2163 (goto-char end)
2164 (allout-hidden-p))))))
2165 (save-match-data
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
2171 ;; done.
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))
2177 (message "Undo!"))
2178 (let (response
2179 (rehide-completely (save-excursion (allout-goto-prefix)
2180 (allout-hidden-p)))
2181 rehide-place)
2183 (save-excursion
2184 (if (condition-case err
2185 ;; Condition case to catch keyboard quits during reads.
2186 (progn
2187 ; Give them a peek where
2188 (save-excursion
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:
2196 (while
2197 (progn
2198 (message (concat "Change inside concealed"
2199 " region - do it? "
2200 "(n or 'y'/'r'eclose)"))
2201 (setq response (read-char))
2202 (not
2203 (cond ((memq response '(?r ?R))
2204 (setq response 'reclose))
2205 ((memq response '(?y ?Y ? ))
2206 (setq response t))
2207 ((memq response '(?n ?N 127))
2208 (setq response nil)
2210 ((eq response ??)
2211 (message
2212 "`r' means `yes, then reclose'")
2213 nil)
2214 (t (message "Please answer y, n, or r")
2215 (sit-for 1)
2216 nil)))))
2217 response)
2218 ('quit nil))
2219 ; Continue:
2220 (if (eq response 'reclose)
2221 (save-excursion
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)))
2229 ; Prevent:
2230 (if rehide-completely
2231 (save-excursion
2232 (if rehide-place (goto-char rehide-place))
2233 (allout-hide-current-entry-completely))
2234 (allout-hide-current-entry))
2235 (error (concat
2236 "Change within concealed region prevented.")))))))
2237 ) ; if
2238 ) ; defun
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
2256 outline commands.
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
2291 ;; insertions:
2292 (numberp (setq prev-from (car prev-cell)))
2293 (numberp (setq prev-to (cdr prev-cell)))
2294 ; Below threshold:
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)
2333 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))
2338 (t 0)))
2339 mapped-binding)
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
2353 64))))))
2354 (if mapped-binding
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))
2364 allout-layout)
2365 (allout-mode t)))
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)
2397 ,flag t)))
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)
2409 font-lock-mode)
2410 font-lock-mode nil)
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)))
2418 ?\r)))
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'"
2445 (car (cdr error))
2446 (car (cdr (cdr error))))
2447 (sit-for 1)
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:
2452 (progn
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
2461 actual quits."
2462 (interactive)
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))
2496 choice)
2497 (save-excursion
2498 (goto-char (allout-current-bullet-pos))
2499 (setq choice (solicit-char-in-string
2500 (format "Select bullet: %s ('%s' default): "
2501 sans-escapes
2502 default-bullet)
2503 sans-escapes
2504 t)))
2505 (message "")
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
2517 (if prefix
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
2535 depth
2536 solicit
2537 number-control
2538 index)
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.
2543 ;;;_ . Doc string:
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',
2551 for instance.
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)."
2586 ;;;_ . Code:
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
2591 ;; specified...
2593 (let* (body
2594 numbering
2595 denumbering
2596 (depth (or depth (allout-depth)))
2597 (header-lead allout-header-prefix)
2598 (bullet-char
2600 ;; Getting value for bullet char is practically the whole job:
2602 (cond
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
2608 ;; bullet-char:
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:
2620 solicit)
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:
2627 got))
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
2635 prior-bullet)))
2636 prior-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
2646 (not denumbering)
2647 (let ((sibling-bullet
2648 (save-excursion
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?
2658 ((and 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)))
2665 ;; Here 'tis:
2666 prior-bullet))
2668 ;; Else, standard bullet per depth:
2669 ((allout-bullet-for-depth depth)))))
2671 (concat header-lead
2672 body
2673 bullet-char
2674 (if numbering
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.
2690 Nuances:
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
2710 from there."
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))
2724 (setq ref-bullet
2725 (if (> allout-recent-prefix-end 1)
2726 (allout-recent-bullet)
2727 ""))
2728 (setq opening-numbered
2729 (save-excursion
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))))
2735 (point)))
2736 dbl-space
2737 doing-beginning)
2739 (if (not opening-on-blank)
2740 ; Positioning and vertical
2741 ; padding - only if not
2742 ; opening-on-blank:
2743 (progn
2744 (goto-char ref-topic)
2745 (setq dbl-space ; Determine double space action:
2746 (or (and (<= relative-depth 0) ; not descending;
2747 (save-excursion
2748 ;; at b-o-b or preceded by a blank line?
2749 (or (> 0 (forward-line -1))
2750 (looking-at "^\\s-*$")
2751 (bobp)))
2752 (save-excursion
2753 ;; succeeded by a blank line?
2754 (allout-end-of-current-subtree)
2755 (bolp)))
2756 (and (= ref-depth 1)
2757 (or before
2758 (= depth 1)
2759 (save-excursion
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))
2770 (if (not (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:
2777 (if doing-beginning
2778 (allout-unprotected (open-line (if dbl-space 2 1)))
2779 (if before
2780 (progn (end-of-line)
2781 (allout-pre-next-preface)
2782 (while (= ?\r (following-char))
2783 (forward-char 1))
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)
2791 (if (bolp)
2792 ;; Blank lines between current header body and next
2793 ;; header - get to last substantive (non-white-space)
2794 ;; line in body:
2795 (re-search-backward "[^ \t\n]" nil t))
2796 (if (save-excursion
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))))
2804 (end-of-line))
2805 ;;(if doing-beginning (goto-char doing-beginning))
2806 (if (not (bobp))
2807 (progn (if (and (not (> depth ref-depth))
2808 (not before))
2809 (allout-unprotected (open-line 1))
2810 (if (> depth ref-depth)
2811 (allout-unprotected (newline 1))
2812 (if dbl-space
2813 (allout-unprotected (open-line 1))
2814 (if (not before)
2815 (allout-unprotected (newline 1))))))
2816 (if dbl-space
2817 (allout-unprotected (newline 1)))
2818 (if (and (not (eobp))
2819 (not (bolp)))
2820 (forward-char 1))))
2822 (insert (concat (allout-make-topic-prefix opening-numbered
2824 depth)
2825 " "))
2827 ;;(if doing-beginning (save-excursion (newline (if dbl-space 2 1))))
2830 (allout-rebullet-heading (and use_sib_bullet ref-bullet);;; solicit
2831 depth ;;; depth
2832 nil ;;; number-control
2833 nil ;;; index
2834 t) (end-of-line)
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."
2856 (interactive "p")
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
2865 one."
2866 (interactive "p")
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."
2875 (interactive "p")
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:
2891 (save-excursion
2892 (beginning-of-line)
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)
2897 (current-column))
2898 ?\ ))))))
2899 (if (or allout-former-auto-filler allout-use-hanging-indents)
2900 (do-auto-fill))))
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
2906 be accommodated.
2908 Note that refill of indented paragraphs is not done."
2910 (save-excursion
2911 (allout-end-of-prefix)
2912 (let* ((new-margin (current-column))
2913 excess old-indent-begin old-indent-end
2914 curr-ind
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:
2921 (allout-unprotected
2922 (save-match-data
2923 (while
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)
2933 old-margin)))
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."
2944 (interactive "p")
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)))))
2949 (while (> arg 0)
2950 (save-excursion (allout-back-to-current-heading)
2951 (allout-end-of-prefix)
2952 (allout-rebullet-heading t ;;; solicit
2953 nil ;;; depth
2954 nil ;;; number-control
2955 nil ;;; index
2956 t)) ;;; do-successors
2957 (setq arg (1- arg))
2958 (if (<= arg 0)
2960 (setq initial-col nil) ; Override positioning back to init col
2961 (if (not backwards)
2962 (allout-next-visible-heading 1)
2963 (allout-goto-prefix)
2964 (allout-next-visible-heading -1))))
2965 (message "Done.")
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
2970 new-depth
2971 number-control
2972 index
2973 do-successors)
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
3003 siblings.
3005 Cf vars `allout-stylish-prefixes', `allout-old-style-prefixes',
3006 and `allout-numbered-bullet', which all affect the behavior of
3007 this function."
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
3016 new-depth
3017 solicit
3018 number-control
3019 index)))
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)))))
3025 ;; Nothing to do:
3028 ;; New prefix probably different from old:
3029 ; get rid of old one:
3030 (allout-unprotected (delete-region mb me))
3031 (goto-char mb)
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]+"))
3037 (allout-unprotected
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:
3050 (if do-successors
3051 (save-excursion
3052 (while (allout-next-sibling new-depth nil)
3053 (setq index
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
3060 index ;;; index
3061 nil))))) ;;;(dont!)do-successors
3062 ) ; (if (and (= current-depth new-depth)...))
3063 ) ; let* ((current-depth (allout-depth))...)
3064 ) ; defun
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."
3072 (interactive "P")
3073 (let ((start-col (current-column))
3074 (was-eol (eolp)))
3075 (save-excursion
3076 ;; Normalize arg:
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
3089 starting-depth
3090 starting-point
3091 index
3092 do-successors)
3094 "Rebullet the topic at point, visible or invisible, and all
3095 contained subtopics. See `allout-rebullet-heading' for rebulleting
3096 behavior.
3098 All arguments are optional.
3100 First arg RELATIVE-DEPTH means to shift the depth of the entire
3101 topic that amount.
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))
3110 (index (or index
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
3121 moving-outwards
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
3129 relative-depth)
3130 nil ;;; number
3131 index ;;; index
3132 ;; Every contained topic will get hit,
3133 ;; and we have to get to outside ones
3134 ;; deliberately:
3135 nil) ;;; do-successors
3136 ;; ... and work on subsequent ones which are at greater depth:
3137 (setq index 0)
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
3145 index))) ;;; index
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
3153 index))) ;;; index
3155 (if on-starting-call
3156 (progn
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
3163 relative-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))
3184 was-eobp)
3185 (while (and (not (eobp))
3186 (allout-depth)
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
3199 nil ;;; depth
3200 nil ;;; number-control
3201 nil ;;; index
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."
3215 (interactive "P")
3217 (save-excursion
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))
3223 (more t))
3224 (while more
3225 (allout-rebullet-heading use-bullet ;;; solicit
3226 depth ;;; depth
3227 t ;;; number-control
3228 index ;;; index
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."
3235 (interactive "p")
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."
3240 (interactive "p")
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."
3247 (interactive "*P")
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:
3253 (kill-line arg)
3254 ;; Ah, have to watch out for adjustments:
3255 (let* ((depth (allout-depth)))
3256 ; Do the kill:
3257 (kill-line arg)
3258 ; Provide some feedback:
3259 (sit-for 0)
3260 (save-excursion
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.
3278 (interactive)
3279 (let* ((beg (prog1 (allout-back-to-current-heading)(beginning-of-line)))
3280 (depth (allout-recent-depth)))
3281 (allout-end-of-current-subtree)
3282 (if (not (eobp))
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:
3288 (save-excursion
3289 (and (allout-next-heading)
3290 (>= (allout-recent-depth) depth))))
3291 (forward-char 1)))
3293 (kill-region beg (point))
3294 (sit-for 0)
3295 (save-excursion
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
3306 topic prefix.
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."
3318 (interactive "*P")
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)
3329 (match-end 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)))))
3334 (if resituate
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))
3339 (adjust-to-depth
3340 ;; Nil if adjustment unnecessary, otherwise depth to which
3341 ;; adjustment should be made:
3342 (save-excursion
3343 (and (goto-char subj-end)
3344 (eolp)
3345 (goto-char subj-beg)
3346 (and (looking-at allout-regexp)
3347 (progn
3348 (beginning-of-line)
3349 (not (= (point) subj-beg)))
3350 (looking-at allout-regexp)
3351 (allout-prefix-data (match-beginning 0)
3352 (match-end 0)))
3353 (allout-recent-depth))))
3354 done
3355 (more t))
3356 (setq rectify-numbering allout-numbered-bullet)
3357 (if adjust-to-depth
3358 ; Do the adjustment:
3359 (progn
3360 (message "... yanking") (sit-for 0)
3361 (save-restriction
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
3369 ; shallowest level,
3370 ; successively excluding the
3371 ; last processed topic from
3372 ; the narrow region:
3373 (while more
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))))
3377 (save-excursion
3378 (allout-rebullet-topic-grunt (- adjust-to-depth
3379 subj-depth))
3380 (allout-depth))
3381 (if (setq more (not (bobp)))
3382 (progn (widen)
3383 (forward-char -1)
3384 (narrow-to-region subj-beg (point))))))
3385 (message "")
3386 ;; Preserve new bullet if it's a distinctive one, otherwise
3387 ;; use old one:
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:
3392 (progn
3393 (beginning-of-line)
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,
3399 ; leaving old one:
3400 (delete-region (point) (+ (point)
3401 prefix-len
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
3409 (progn
3410 (save-excursion
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
3419 nil ;;; index
3421 (message ""))))
3422 (if (not resituate)
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
3436 topic prefix.
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."
3453 (interactive "*P")
3454 (setq this-command 'yank)
3455 (yank arg)
3456 (if (allout-mode-p)
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..."
3467 (interactive "*p")
3468 (setq this-command 'yank)
3469 (yank-pop arg)
3470 (if (allout-mode-p)
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')."
3480 (interactive)
3481 (if (not allout-file-xref-bullet)
3482 (error
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)
3487 (let (file-name)
3488 (save-excursion
3489 (let* ((text-start allout-recent-prefix-end)
3490 (heading-end (progn (end-of-line) (point))))
3491 (goto-char text-start)
3492 (setq file-name
3493 (if (re-search-forward "\\s-\\(\\S-*\\)" heading-end t)
3494 (buffer-substring (match-beginning 1) (match-end 1))))))
3495 (setq file-name
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? "
3506 file-name))
3507 (error "%s not found and can't be created" file-name)))
3508 (condition-case failure
3509 (find-file-other-window file-name)
3510 ('error failure))
3511 (error "%s not found" file-name))
3517 ;;;_ #6 Exposure Control
3519 ;;;_ - Fundamental
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."
3526 (save-excursion
3527 (allout-back-to-current-heading)
3528 (allout-flag-region (point)
3529 (progn (allout-end-of-current-subtree) (1- (point)))
3530 flag)))
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."
3542 (interactive)
3543 (save-excursion
3544 (let ((at (point))
3545 beg end)
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:
3551 (point)
3552 ;; or we're in body - include it:
3553 (max beg (or (allout-pre-next-preface) (point))))))
3554 (allout-flag-region beg end ?\n)
3555 (list beg end))))
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?)"
3574 (interactive "p")
3575 (let (max-pos)
3576 (if (and (not strict)
3577 (allout-hidden-p))
3579 (progn (allout-show-to-offshoot) ; Point's concealed, open to
3580 ; expose it.
3581 ;; Then recurse, but with "strict" set so we don't
3582 ;; infinite regress:
3583 (setq max-pos (allout-show-children level t)))
3585 (save-excursion
3586 (save-restriction
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.
3594 (progn
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)))))
3599 (while to-reveal
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."
3612 (interactive)
3613 (save-excursion
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))
3618 (point)
3619 (1- (point))))
3620 ?\r)))
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'."
3628 (interactive)
3629 (save-excursion
3630 (let ((orig-pt (point))
3631 (orig-pref (allout-goto-prefix))
3632 (last-at (point))
3633 bag-it)
3634 (while (or bag-it (= (preceding-char) ?\r))
3635 (beginning-of-line)
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)
3641 (goto-char orig-pt)
3642 (setq bag-it t)
3643 (beep)
3644 (message "%s: %s"
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."
3655 (interactive)
3656 (allout-back-to-current-heading)
3657 (save-excursion
3658 (allout-flag-region (point)
3659 (progn (allout-end-of-current-entry) (point))
3660 ?\r)))
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."
3666 (interactive "P")
3667 (if arg
3668 (allout-hide-current-entry)
3669 (save-excursion
3670 (allout-flag-region (point)
3671 (progn (allout-end-of-current-entry) (point))
3672 ?\n))))
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."
3680 (interactive)
3681 (save-excursion
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))
3686 (point)
3687 (1- (point))))
3688 ?\r)))
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."
3693 (interactive "P")
3694 (save-excursion
3695 (if (<= (allout-current-depth) 0)
3696 ;; Outside any topics - try to get to the first:
3697 (if (not (allout-next-heading))
3698 (error "No topics")
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))
3702 (if (not arg)
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
3711 and its siblings.
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."
3716 (interactive)
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)
3723 (goto-char from)
3724 (if (and (= orig-eol (progn (goto-char orig-eol)
3725 (end-of-line)
3726 (point)))
3727 (not just-close)
3728 ;; Structure didn't change - try hiding current level:
3729 (goto-char from)
3730 (if (allout-up-current-level 1 t)
3732 (goto-char 0)
3733 (let ((msg
3734 "Top-level topic already closed - closing siblings..."))
3735 (message msg)
3736 (allout-expose-topic '(0 :))
3737 (message (concat msg " Done.")))
3738 nil)
3739 (/= (allout-recent-depth) 0))
3740 (allout-hide-current-subtree))
3741 (goto-char from)))
3742 ;;;_ > allout-show-current-branches ()
3743 (defun allout-show-current-branches ()
3744 "Show all subheadings of this heading, but not their bodies."
3745 (interactive)
3746 (beginning-of-line)
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."
3751 (interactive)
3752 (allout-back-to-current-heading)
3753 (allout-hide-region-body (point) (progn (allout-end-of-current-subtree)
3754 (point))))
3756 ;;;_ - Region and beyond
3757 ;;;_ > allout-show-all ()
3758 (defun allout-show-all ()
3759 "Show all of the text in the buffer."
3760 (interactive)
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."
3767 (interactive)
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."
3772 (save-excursion
3773 (save-restriction
3774 (narrow-to-region start end)
3775 (goto-char (point-min))
3776 (while (not (eobp))
3777 (allout-flag-region (point)
3778 (progn (allout-pre-next-preface) (point)) ?\r)
3779 (if (not (eobp))
3780 (forward-char
3781 (if (looking-at "[\n\r][\n\r]")
3782 2 1)))))))
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
3814 that level.
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.
3818 : - `repeat'
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.
3828 Examples:
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
3836 close the last one.
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))
3846 (max-pos 0)
3847 prev-elem curr-elem
3848 stay done
3849 snug-back
3851 (while spec
3852 (setq prev-elem curr-elem
3853 curr-elem (car spec)
3854 spec (cdr 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))
3865 ((eq curr-elem ':)
3866 (setq stay t)
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))
3872 (length spec))))
3873 (if (< 0 residue)
3874 ;; Some residue - cover it with prev-elem:
3875 (setq spec (append (make-list residue prev-elem)
3876 spec)))))))
3877 ((numberp curr-elem)
3878 (if (and (>= 0 curr-elem) (allout-visible-p))
3879 (save-excursion (allout-hide-current-subtree t)
3880 (if (> 0 curr-elem)
3882 (if (> allout-recent-end-of-subtree max-pos)
3883 (setq 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)))))
3889 ((listp curr-elem)
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))))
3900 max-pos)))
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
3905 format) instead.
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.
3924 - 0 just closes
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))
3938 done
3939 max-pos)
3940 (cond ((null spec) nil)
3941 ((symbolp spec)
3942 (if (eq spec '*) (allout-show-current-subtree))
3943 (if (eq spec '+) (allout-show-current-branches))
3944 (if (eq spec '-) (allout-show-current-entry)))
3945 ((numberp spec)
3946 (if (>= 0 spec)
3947 (save-excursion (allout-hide-current-subtree t)
3948 (end-of-line)
3949 (if (or (not max-pos)
3950 (> (point) max-pos))
3951 (setq max-pos (point)))
3952 (if (> 0 spec)
3953 (setq spec (* -1 spec)))))
3954 (if (> spec 0)
3955 (allout-show-children spec)))
3956 ((listp 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))
3961 got)
3962 (setq max-pos (allout-old-expose-topic (car spec)))
3963 (setq spec (cdr spec))
3964 (if (and 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)))
3974 (end-of-line)
3975 (allout-next-sibling depth)))
3976 (allout-old-expose-topic (car followers))
3977 (setq followers (cdr followers)))
3978 max-pos))
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'.
3989 Examples:
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."
4029 (let ((delim ".")
4030 result
4031 numstr
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)))
4041 (setq delim " ")
4042 ;; Take care of the indentation:
4043 (if flat-index
4044 (progn
4045 (while flat-index
4046 (setq result
4047 (cons delim
4048 (cons (make-string
4049 (1+ (truncate (if (zerop (car flat-index))
4051 (log10 (car flat-index)))))
4053 result)))
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."
4061 (let ((delim ".")
4062 result)
4063 (while flat-index
4064 (setq result (cons (int-to-string (car flat-index))
4065 (if result
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."
4072 (let ((delim ".")
4073 result
4074 numstr)
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)))
4081 (setq delim " ")
4082 ;; Take care of the indentation:
4083 (if flat-index
4084 (progn
4085 (while flat-index
4086 (setq result
4087 (cons delim
4088 (cons (make-string
4089 (1+ (truncate (if (zerop (car flat-index))
4091 (log10 (car flat-index)))))
4093 result)))
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
4104 the subject region.
4106 Optional START and END indicate bounds of region.
4108 optional arg, FORMAT, designates an alternate presentation form for
4109 the prefix:
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
4121 bullet.
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."
4126 (interactive "r")
4127 (save-excursion
4128 (let*
4129 ;; state vars:
4130 (strings prefix pad result depth new-depth out gone-out bullet beg
4131 next done)
4133 (goto-char start)
4134 (beginning-of-line)
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))
4150 (setq gone-out out
4151 out (< new-depth depth))
4152 (beginning-of-line)
4153 (setq next (point))
4154 (goto-char beg)
4155 (setq strings nil)
4156 (while (> next (point)) ; Get all the exposed text in
4157 (setq strings
4158 (cons (buffer-substring
4160 ;To hidden text or end of line:
4161 (progn
4162 (search-forward "\r"
4163 (save-excursion (end-of-line)
4164 (point))
4166 (if (= (preceding-char) ?\r)
4167 (1- (point))
4168 (point))))
4169 strings))
4170 (if (< (point) next) ; Resume from after hid text, if any.
4171 (forward-line 1))
4172 (setq beg (point)))
4173 ;; Accumulate list for this topic:
4174 (setq strings (nreverse strings))
4175 (setq result
4176 (cons
4177 (if format
4178 (let ((special (if (string-match
4179 (regexp-quote bullet)
4180 allout-distinctive-bullets-string)
4181 bullet)))
4182 (cond ((listp format)
4183 (list depth
4184 (if allout-abbreviate-flattened-numbering
4185 (allout-stringify-flat-index format
4186 gone-out)
4187 (allout-stringify-flat-index-plain
4188 format))
4189 strings
4190 special))
4191 ((eq format 'indent)
4192 (if special
4193 (list depth
4194 (concat (make-string (1+ depth) ? )
4195 (substring prefix -1))
4196 strings)
4197 (list depth
4198 (make-string depth ? )
4199 strings)))
4200 (t (error "allout-listify-exposed: %s %s"
4201 "invalid format" format))))
4202 (list depth prefix strings))
4203 result))
4204 ;; Reasses format, if any:
4205 (if (and format (listp format))
4206 (cond ((= new-depth depth)
4207 (setq format (cons (1+ (car format))
4208 (cdr format))))
4209 ((> new-depth depth) ; descending - assume by 1:
4210 (setq format (cons 1 format)))
4212 ; Pop the residue:
4213 (while (< new-depth depth)
4214 (setq format (cdr format))
4215 (setq depth (1- depth)))
4216 ; And increment the current one:
4217 (setq format
4218 (cons (1+ (or (car format)
4219 -1))
4220 (cdr 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
4224 ;;; tobuf format)
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.
4243 Defaults:
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*\"
4249 FORMAT: nil"
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))))
4258 (if frombuf
4259 (if (not (bufferp frombuf))
4260 ;; Specified but not a buffer - get it:
4261 (let ((got (get-buffer frombuf)))
4262 (if (not got)
4263 (error (concat "allout-process-exposed: source buffer "
4264 frombuf
4265 " not found."))
4266 (setq frombuf got))))
4267 ;; not specified - default it:
4268 (setq frombuf (current-buffer)))
4269 (if tobuf
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*")))
4274 (if (listp format)
4275 (nreverse format))
4277 (let* ((listified
4278 (progn (set-buffer frombuf)
4279 (allout-listify-exposed from to format))))
4280 (set-buffer tobuf)
4281 (mapcar func listified)
4282 (pop-to-buffer tobuf)))
4284 ;;;_ - Copy exposed
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
4298 (car listified)
4299 (setq listified (cdr listified))))
4300 (text (prog1
4301 (car listified)
4302 (setq listified (cdr listified))))
4303 (bullet-plus (car listified)))
4304 (insert prefix)
4305 (if bullet-plus (insert (concat " " bullet-plus)))
4306 (while text
4307 (insert (car text))
4308 (if (setq text (cdr text))
4309 (insert "\n")))
4310 (insert "\n")))
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."
4332 (interactive "P")
4333 (if (not tobuf)
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))
4339 (start-list ()))
4340 (if (eq format 'flat)
4341 (setq format (if arg (save-excursion
4342 (goto-char beg)
4343 (allout-topic-flat-index))
4344 '(1))))
4345 (save-excursion (set-buffer tobuf)(erase-buffer))
4346 (allout-process-exposed 'allout-insert-listified
4349 (current-buffer)
4350 tobuf
4351 format start-list)
4352 (goto-char (point-min))
4353 (pop-to-buffer buf)
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
4368 used verbatim."
4369 (interactive "P")
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
4384 used verbatim."
4385 (interactive "P")
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
4395 (lambda (char)
4396 (cond ((memq char '(?\\ ?$ ?% ?# ?& ?{ ?} ?_ ?^ ?- ?*))
4397 (concat "\\char" (number-to-string char) "{}"))
4398 ((= char ?\n) "\\\\")
4399 (t (char-to-string char)))))
4401 ""))
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."
4409 (beginning-of-line)
4410 (let ((beg (point))
4411 (end (progn (end-of-line)(point))))
4412 (goto-char beg)
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))
4418 (insert "\\")
4419 (setq end (1+ end))
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.
4426 (set-buffer buf)
4427 (let ((doc-style (format "\n\\documentstyle{%s}\n"
4428 "report"))
4429 (page-numbering (if allout-number-pages
4430 "\\pagestyle{empty}\n"
4431 ""))
4432 (linesdef (concat "\\def\\beginlines{"
4433 "\\par\\begingroup\\nobreak\\medskip"
4434 "\\parindent=0pt\n"
4435 " \\kern1pt\\nobreak \\obeylines \\obeyspaces "
4436 "\\everypar{\\strut}}\n"
4437 "\\def\\endlines{"
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}{"
4450 allout-indent
4451 "}\n"))
4452 (oneheadline (format "%s%s%s%s%s%s%s"
4453 "\\newcommand{\\OneHeadLine}[3]{%\n"
4454 "\\noindent%\n"
4455 "\\hspace*{#2\\stepsize}%\n"
4456 "\\labelcmd{#1}\\hspace*{.2cm}"
4457 "\\headlinecmd{#3}\\\\["
4458 allout-line-skip
4459 "]\n}\n"))
4460 (onebodyline (format "%s%s%s%s%s%s"
4461 "\\newcommand{\\OneBodyLine}[2]{%\n"
4462 "\\noindent%\n"
4463 "\\hspace*{#1\\stepsize}%\n"
4464 "\\bodylinecmd{#2}\\\\["
4465 allout-line-skip
4466 "]\n}\n"))
4467 (begindoc "\\begin{document}\n\\begin{center}\n")
4468 (title (format "%s%s%s%s"
4469 "\\titlecmd{"
4470 (allout-latex-verb-quote (if allout-title
4471 (condition-case err
4472 (eval allout-title)
4473 ('error "<unnamed buffer>"))
4474 "Unnamed Outline"))
4475 "}\n"
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
4481 page-numbering
4482 titlecmd
4483 labelcmd
4484 headlinecmd
4485 bodylinecmd
4486 setlength
4487 oneheadline
4488 onebodyline
4489 begindoc
4490 title
4491 hsize
4492 hoffset
4493 vspace)
4495 ;;;_ > allout-insert-latex-trailer (buf)
4496 (defun allout-insert-latex-trailer (buf)
4497 "Insert concluding latex commands at point in BUFFER."
4498 (set-buffer buf)
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))
4508 (curr-line)
4509 body-content bop)
4510 ; Do the head line:
4511 (insert (concat "\\OneHeadLine{\\verb\1 "
4512 (allout-latex-verb-quote bullet)
4513 "\1}{"
4514 depth
4515 "}{\\verb\1 "
4516 (if head-line
4517 (allout-latex-verb-quote head-line)
4519 "\1}\n"))
4520 (if (not body-lines)
4522 ;;(insert "\\beginlines\n")
4523 (insert "\\begin{verbatim}\n")
4524 (while body-lines
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,
4531 ; it's special:
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) "|")
4538 (insert curr-line)
4539 (allout-latex-verbatim-quote-curr-line)
4540 (insert "\n")
4541 (setq body-lines (cdr body-lines)))
4542 (if body-content
4543 (setq body-content nil)
4544 (forward-char -1)
4545 (insert "\\ ")
4546 (forward-char 1))
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."
4558 (interactive "P")
4559 (if (not tobuf)
4560 (setq tobuf
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)))
4566 (set-buffer tobuf)
4567 (erase-buffer)
4568 (allout-insert-latex-header tobuf)
4569 (goto-char (point-max))
4570 (allout-process-exposed 'allout-latexify-one-item
4574 tobuf)
4575 (goto-char (point-max))
4576 (allout-insert-latex-trailer tobuf)
4577 (goto-char (point-min))
4578 (pop-to-buffer buf)
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."
4585 (interactive)
4586 (beginning-of-line)
4587 (allout-goto-prefix)
4588 (push-mark (point))
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."
4600 (interactive "P")
4602 (allout-mode t)
4604 (save-excursion
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'."))
4611 (forward-line 1)
4612 (goto-char (point-max))
4613 (open-line 1)
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"
4622 (or allout-layout
4623 '(-1 : 0))))
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)
4633 got)
4635 (while (not got)
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.)
4640 (setq got
4641 (char-to-string (let ((cursor-in-echo-area nil)) (read-char))))
4643 (setq got
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
4652 " ...pick from: "
4653 string
4654 ""))
4655 nil))))
4656 ;; got something out of loop - return it:
4657 got)
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
4664 single backslash.
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)
4675 nil))
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)
4685 '(region-active-p)
4686 'mark-active))
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)))
4703 (set hook
4704 (if append
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)
4715 (mark-marker)))
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."
4721 (interactive)
4722 (if (not 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
4730 "[ \t]*"
4731 bullet)))
4732 (isearch-repeat 'forward)
4733 (isearch-mode t)))
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).
4743 ;;;Local variables:
4744 ;;;allout-layout: (0 : -1 -1 0)
4745 ;;;End:
4747 ;;; arch-tag: cf38fbc3-c044-450f-8bff-afed8ba5681c
4748 ;;; allout.el ends here