(grep-regexp-alist): Set 5th arg `TYPE' to
[emacs.git] / lisp / allout.el
blob6f5d06cf79ed3a8d8ad99ae0887767c82f4b579e
1 ;;; allout.el --- extensive outline mode for use alone and with other modes
3 ;; Copyright (C) 1992, 93, 94, 2001, 02, 2004 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., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, 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
72 :version "22.1")
74 ;;;_ + Layout, Mode, and Topic Header Configuration
76 ;;;_ = allout-auto-activation
77 (defcustom allout-auto-activation nil
78 "*Regulates auto-activation modality of allout outlines - see `allout-init'.
80 Setq-default by `allout-init' to regulate whether or not allout
81 outline mode is automatically activated when the buffer-specific
82 variable `allout-layout' is non-nil, and whether or not the layout
83 dictated by `allout-layout' should be imposed on mode activation.
85 With value t, auto-mode-activation and auto-layout are enabled.
86 \(This also depends on `allout-find-file-hook' being installed in
87 `find-file-hook', which is also done by `allout-init'.)
89 With value `ask', auto-mode-activation is enabled, and endorsement for
90 performing auto-layout is asked of the user each time.
92 With value `activate', only auto-mode-activation is enabled,
93 auto-layout is not.
95 With value nil, neither auto-mode-activation nor auto-layout are
96 enabled.
98 See the docstring for `allout-init' for the proper interface to
99 this variable."
100 :type '(choice (const :tag "On" t)
101 (const :tag "Ask about layout" "ask")
102 (const :tag "Mode only" "activate")
103 (const :tag "Off" nil))
104 :group 'allout)
105 ;;;_ = allout-layout
106 (defvar allout-layout nil
107 "*Layout specification and provisional mode trigger for allout outlines.
109 Buffer-specific.
111 A list value specifies a default layout for the current buffer, to be
112 applied upon activation of `allout-mode'. Any non-nil value will
113 automatically trigger `allout-mode', provided `allout-init'
114 has been called to enable it.
116 See the docstring for `allout-init' for details on setting up for
117 auto-mode-activation, and for `allout-expose-topic' for the format of
118 the layout specification.
120 You can associate a particular outline layout with a file by setting
121 this var via the file's local variables. For example, the following
122 lines at the bottom of an Emacs Lisp file:
124 ;;;Local variables:
125 ;;;allout-layout: \(0 : -1 -1 0)
126 ;;;End:
128 will, modulo the above-mentioned conditions, cause the mode to be
129 activated when the file is visited, followed by the equivalent of
130 `\(allout-expose-topic 0 : -1 -1 0)'. \(This is the layout used for
131 the allout.el, itself.)
133 Also, allout's mode-specific provisions will make topic prefixes default
134 to the comment-start string, if any, of the language of the file. This
135 is modulo the setting of `allout-use-mode-specific-leader', which see.")
136 (make-variable-buffer-local 'allout-layout)
137 ;;;_ = allout-show-bodies
138 (defcustom allout-show-bodies nil
139 "*If non-nil, show entire body when exposing a topic, rather than
140 just the header."
141 :type 'boolean
142 :group 'allout)
143 (make-variable-buffer-local 'allout-show-bodies)
145 ;;;_ = allout-header-prefix
146 (defcustom allout-header-prefix "."
147 "*Leading string which helps distinguish topic headers.
149 Outline topic header lines are identified by a leading topic
150 header prefix, which mostly have the value of this var at their front.
151 \(Level 1 topics are exceptions. They consist of only a single
152 character, which is typically set to the `allout-primary-bullet'. Many
153 outlines start at level 2 to avoid this discrepancy."
154 :type 'string
155 :group 'allout)
156 (make-variable-buffer-local 'allout-header-prefix)
157 ;;;_ = allout-primary-bullet
158 (defcustom allout-primary-bullet "*"
159 "Bullet used for top-level outline topics.
161 Outline topic header lines are identified by a leading topic header
162 prefix, which is concluded by bullets that includes the value of this
163 var and the respective allout-*-bullets-string vars.
165 The value of an asterisk (`*') provides for backwards compatibility
166 with the original Emacs outline mode. See `allout-plain-bullets-string'
167 and `allout-distinctive-bullets-string' for the range of available
168 bullets."
169 :type 'string
170 :group 'allout)
171 (make-variable-buffer-local 'allout-primary-bullet)
172 ;;;_ = allout-plain-bullets-string
173 (defcustom allout-plain-bullets-string ".:,;"
174 "*The bullets normally used in outline topic prefixes.
176 See `allout-distinctive-bullets-string' for the other kind of
177 bullets.
179 DO NOT include the close-square-bracket, `]', as a bullet.
181 Outline mode has to be reactivated in order for changes to the value
182 of this var to take effect."
183 :type 'string
184 :group 'allout)
185 (make-variable-buffer-local 'allout-plain-bullets-string)
186 ;;;_ = allout-distinctive-bullets-string
187 (defcustom allout-distinctive-bullets-string "*+-=>([{}&!?#%\"X@$~_\\"
188 "*Persistent outline header bullets used to distinguish special topics.
190 These bullets are used to distinguish topics from the run-of-the-mill
191 ones. They are not used in the standard topic headers created by
192 the topic-opening, shifting, and rebulleting \(eg, on topic shift,
193 topic paste, blanket rebulleting) routines, but are offered among the
194 choices for rebulleting. They are not altered by the above automatic
195 rebulleting, so they can be used to characterize topics, eg:
197 `?' question topics
198 `\(' parenthetic comment \(with a matching close paren inside)
199 `[' meta-note \(with a matching close ] inside)
200 `\"' a quote
201 `=' value settings
202 `~' \"more or less\"
204 ... just for example. (`#' typically has a special meaning to the
205 software, according to the value of `allout-numbered-bullet'.)
207 See `allout-plain-bullets-string' for the selection of
208 alternating bullets.
210 You must run `set-allout-regexp' in order for outline mode to
211 reconcile to changes of this value.
213 DO NOT include the close-square-bracket, `]', on either of the bullet
214 strings."
215 :type 'string
216 :group 'allout)
217 (make-variable-buffer-local 'allout-distinctive-bullets-string)
219 ;;;_ = allout-use-mode-specific-leader
220 (defcustom allout-use-mode-specific-leader t
221 "*When non-nil, use mode-specific topic-header prefixes.
223 Allout outline mode will use the mode-specific `allout-mode-leaders'
224 and/or comment-start string, if any, to lead the topic prefix string,
225 so topic headers look like comments in the programming language.
227 String values are used as they stand.
229 Value t means to first check for assoc value in `allout-mode-leaders'
230 alist, then use comment-start string, if any, then use default \(`.').
231 \(See note about use of comment-start strings, below.)
233 Set to the symbol for either of `allout-mode-leaders' or
234 `comment-start' to use only one of them, respectively.
236 Value nil means to always use the default \(`.').
238 comment-start strings that do not end in spaces are tripled, and an
239 `_' underscore is tacked on the end, to distinguish them from regular
240 comment strings. comment-start strings that do end in spaces are not
241 tripled, but an underscore is substituted for the space. [This
242 presumes that the space is for appearance, not comment syntax. You
243 can use `allout-mode-leaders' to override this behavior, when
244 incorrect.]"
245 :type '(choice (const t) (const nil) string
246 (const allout-mode-leaders)
247 (const comment-start))
248 :group 'allout)
249 ;;;_ = allout-mode-leaders
250 (defvar allout-mode-leaders '()
251 "Specific allout-prefix leading strings per major modes.
253 Entries will be used instead or in lieu of mode-specific
254 comment-start strings. See also `allout-use-mode-specific-leader'.
256 If you're constructing a string that will comment-out outline
257 structuring so it can be included in program code, append an extra
258 character, like an \"_\" underscore, to distinguish the lead string
259 from regular comments that start at bol.")
261 ;;;_ = allout-old-style-prefixes
262 (defcustom allout-old-style-prefixes nil
263 "*When non-nil, use only old-and-crusty `outline-mode' `*' topic prefixes.
265 Non-nil restricts the topic creation and modification
266 functions to asterix-padded prefixes, so they look exactly
267 like the original Emacs-outline style prefixes.
269 Whatever the setting of this variable, both old and new style prefixes
270 are always respected by the topic maneuvering functions."
271 :type 'boolean
272 :group 'allout)
273 (make-variable-buffer-local 'allout-old-style-prefixes)
274 ;;;_ = allout-stylish-prefixes - alternating bullets
275 (defcustom allout-stylish-prefixes t
276 "*Do fancy stuff with topic prefix bullets according to level, etc.
278 Non-nil enables topic creation, modification, and repositioning
279 functions to vary the topic bullet char (the char that marks the topic
280 depth) just preceding the start of the topic text) according to level.
281 Otherwise, only asterisks (`*') and distinctive bullets are used.
283 This is how an outline can look (but sans indentation) with stylish
284 prefixes:
286 * Top level
287 .* A topic
288 . + One level 3 subtopic
289 . . One level 4 subtopic
290 . . A second 4 subtopic
291 . + Another level 3 subtopic
292 . #1 A numbered level 4 subtopic
293 . #2 Another
294 . ! Another level 4 subtopic with a different distinctive bullet
295 . #4 And another numbered level 4 subtopic
297 This would be an outline with stylish prefixes inhibited (but the
298 numbered and other distinctive bullets retained):
300 * Top level
301 .* A topic
302 . * One level 3 subtopic
303 . * One level 4 subtopic
304 . * A second 4 subtopic
305 . * Another level 3 subtopic
306 . #1 A numbered level 4 subtopic
307 . #2 Another
308 . ! Another level 4 subtopic with a different distinctive bullet
309 . #4 And another numbered level 4 subtopic
311 Stylish and constant prefixes (as well as old-style prefixes) are
312 always respected by the topic maneuvering functions, regardless of
313 this variable setting.
315 The setting of this var is not relevant when `allout-old-style-prefixes'
316 is non-nil."
317 :type 'boolean
318 :group 'allout)
319 (make-variable-buffer-local 'allout-stylish-prefixes)
321 ;;;_ = allout-numbered-bullet
322 (defcustom allout-numbered-bullet "#"
323 "*String designating bullet of topics that have auto-numbering; nil for none.
325 Topics having this bullet have automatic maintenance of a sibling
326 sequence-number tacked on, just after the bullet. Conventionally set
327 to \"#\", you can set it to a bullet of your choice. A nil value
328 disables numbering maintenance."
329 :type '(choice (const nil) string)
330 :group 'allout)
331 (make-variable-buffer-local 'allout-numbered-bullet)
332 ;;;_ = allout-file-xref-bullet
333 (defcustom allout-file-xref-bullet "@"
334 "*Bullet signifying file cross-references, for `allout-resolve-xref'.
336 Set this var to the bullet you want to use for file cross-references."
337 :type '(choice (const nil) string)
338 :group 'allout)
340 ;;;_ = allout-presentation-padding
341 (defcustom allout-presentation-padding 2
342 "*Presentation-format white-space padding factor, for greater indent."
343 :type 'integer
344 :group 'allout)
346 (make-variable-buffer-local 'allout-presentation-padding)
348 ;;;_ = allout-abbreviate-flattened-numbering
349 (defcustom allout-abbreviate-flattened-numbering nil
350 "*If non-nil, `allout-flatten-exposed-to-buffer' abbreviates topic
351 numbers to minimal amount with some context. Otherwise, entire
352 numbers are always used."
353 :type 'boolean
354 :group 'allout)
356 ;;;_ + LaTeX formatting
357 ;;;_ - allout-number-pages
358 (defcustom allout-number-pages nil
359 "*Non-nil turns on page numbering for LaTeX formatting of an outline."
360 :type 'boolean
361 :group 'allout)
362 ;;;_ - allout-label-style
363 (defcustom allout-label-style "\\large\\bf"
364 "*Font and size of labels for LaTeX formatting of an outline."
365 :type 'string
366 :group 'allout)
367 ;;;_ - allout-head-line-style
368 (defcustom allout-head-line-style "\\large\\sl "
369 "*Font and size of entries for LaTeX formatting of an outline."
370 :type 'string
371 :group 'allout)
372 ;;;_ - allout-body-line-style
373 (defcustom allout-body-line-style " "
374 "*Font and size of entries for LaTeX formatting of an outline."
375 :type 'string
376 :group 'allout)
377 ;;;_ - allout-title-style
378 (defcustom allout-title-style "\\Large\\bf"
379 "*Font and size of titles for LaTeX formatting of an outline."
380 :type 'string
381 :group 'allout)
382 ;;;_ - allout-title
383 (defcustom allout-title '(or buffer-file-name (current-buffer-name))
384 "*Expression to be evaluated to determine the title for LaTeX
385 formatted copy."
386 :type 'sexp
387 :group 'allout)
388 ;;;_ - allout-line-skip
389 (defcustom allout-line-skip ".05cm"
390 "*Space between lines for LaTeX formatting of an outline."
391 :type 'string
392 :group 'allout)
393 ;;;_ - allout-indent
394 (defcustom allout-indent ".3cm"
395 "*LaTeX formatted depth-indent spacing."
396 :type 'string
397 :group 'allout)
399 ;;;_ + Miscellaneous customization
401 ;;;_ = allout-command-prefix
402 (defcustom allout-command-prefix "\C-c"
403 "*Key sequence to be used as prefix for outline mode command key bindings."
404 :type 'string
405 :group 'allout)
407 ;;;_ = allout-keybindings-list
408 ;;; You have to reactivate allout-mode - `(allout-mode t)' - to
409 ;;; institute changes to this var.
410 (defvar allout-keybindings-list ()
411 "*List of `allout-mode' key / function bindings, for `allout-mode-map'.
413 String or vector key will be prefaced with `allout-command-prefix',
414 unless optional third, non-nil element is present.")
415 (setq allout-keybindings-list
417 ; Motion commands:
418 ("\C-n" allout-next-visible-heading)
419 ("\C-p" allout-previous-visible-heading)
420 ("\C-u" allout-up-current-level)
421 ("\C-f" allout-forward-current-level)
422 ("\C-b" allout-backward-current-level)
423 ("\C-a" allout-beginning-of-current-entry)
424 ("\C-e" allout-end-of-current-entry)
425 ; Exposure commands:
426 ("\C-i" allout-show-children)
427 ("\C-s" allout-show-current-subtree)
428 ("\C-h" allout-hide-current-subtree)
429 ("\C-o" allout-show-current-entry)
430 ("!" allout-show-all)
431 ; Alteration commands:
432 (" " allout-open-sibtopic)
433 ("." allout-open-subtopic)
434 ("," allout-open-supertopic)
435 ("'" allout-shift-in)
436 (">" allout-shift-in)
437 ("<" allout-shift-out)
438 ("\C-m" allout-rebullet-topic)
439 ("*" allout-rebullet-current-heading)
440 ("#" allout-number-siblings)
441 ("\C-k" allout-kill-line t)
442 ("\C-y" allout-yank t)
443 ("\M-y" allout-yank-pop t)
444 ("\C-k" allout-kill-topic)
445 ; Miscellaneous commands:
446 ;([?\C-\ ] allout-mark-topic)
447 ("@" allout-resolve-xref)
448 ("=c" allout-copy-exposed-to-buffer)
449 ("=i" allout-indented-exposed-to-buffer)
450 ("=t" allout-latexify-exposed)
451 ("=p" allout-flatten-exposed-to-buffer)))
453 ;;;_ = allout-isearch-dynamic-expose
454 (defcustom allout-isearch-dynamic-expose t
455 "*Non-nil enable dynamic exposure of hidden incremental-search
456 targets as they're encountered."
457 :type 'boolean
458 :group 'allout)
459 (make-variable-buffer-local 'allout-isearch-dynamic-expose)
461 ;;;_ = allout-use-hanging-indents
462 (defcustom allout-use-hanging-indents t
463 "*If non-nil, topic body text auto-indent defaults to indent of the header.
464 Ie, it is indented to be just past the header prefix. This is
465 relevant mostly for use with indented-text-mode, or other situations
466 where auto-fill occurs.
468 \[This feature no longer depends in any way on the `filladapt.el'
469 lisp-archive package.\]"
470 :type 'boolean
471 :group 'allout)
472 (make-variable-buffer-local 'allout-use-hanging-indents)
474 ;;;_ = allout-reindent-bodies
475 (defcustom allout-reindent-bodies (if allout-use-hanging-indents
476 'text)
477 "*Non-nil enables auto-adjust of topic body hanging indent with depth shifts.
479 When active, topic body lines that are indented even with or beyond
480 their topic header are reindented to correspond with depth shifts of
481 the header.
483 A value of t enables reindent in non-programming-code buffers, ie
484 those that do not have the variable `comment-start' set. A value of
485 `force' enables reindent whether or not `comment-start' is set."
486 :type '(choice (const nil) (const t) (const text) (const force))
487 :group 'allout)
489 (make-variable-buffer-local 'allout-reindent-bodies)
491 ;;;_ = allout-inhibit-protection
492 (defcustom allout-inhibit-protection nil
493 "*Non-nil disables warnings and confirmation-checks for concealed-text edits.
495 Outline mode uses Emacs change-triggered functions to detect unruly
496 changes to concealed regions. Set this var non-nil to disable the
497 protection, potentially increasing text-entry responsiveness a bit.
499 This var takes effect at `allout-mode' activation, so you may have to
500 deactivate and then reactivate the mode if you want to toggle the
501 behavior."
502 :type 'boolean
503 :group 'allout)
505 ;;;_* CODE - no user customizations below.
507 ;;;_ #1 Internal Outline Formatting and Configuration
508 ;;;_ : Version
509 ;;;_ = allout-version
510 (defvar allout-version
511 (let ((rcs-rev "$Revision$"))
512 (condition-case err
513 (save-match-data
514 (string-match "Revision: \\([0-9]+\\.[0-9]+\\)" rcs-rev)
515 (substring rcs-rev (match-beginning 1) (match-end 1)))
516 ('error rcs-rev)))
517 "Revision number of currently loaded outline package. \(allout.el)")
518 ;;;_ > allout-version
519 (defun allout-version (&optional here)
520 "Return string describing the loaded outline version."
521 (interactive "P")
522 (let ((msg (concat "Allout Outline Mode v " allout-version)))
523 (if here (insert msg))
524 (message "%s" msg)
525 msg))
526 ;;;_ : Topic header format
527 ;;;_ = allout-regexp
528 (defvar allout-regexp ""
529 "*Regular expression to match the beginning of a heading line.
531 Any line whose beginning matches this regexp is considered a
532 heading. This var is set according to the user configuration vars
533 by `set-allout-regexp'.")
534 (make-variable-buffer-local 'allout-regexp)
535 ;;;_ = allout-bullets-string
536 (defvar allout-bullets-string ""
537 "A string dictating the valid set of outline topic bullets.
539 This var should *not* be set by the user - it is set by `set-allout-regexp',
540 and is produced from the elements of `allout-plain-bullets-string'
541 and `allout-distinctive-bullets-string'.")
542 (make-variable-buffer-local 'allout-bullets-string)
543 ;;;_ = allout-bullets-string-len
544 (defvar allout-bullets-string-len 0
545 "Length of current buffers' `allout-plain-bullets-string'.")
546 (make-variable-buffer-local 'allout-bullets-string-len)
547 ;;;_ = allout-line-boundary-regexp
548 (defvar allout-line-boundary-regexp ()
549 "`allout-regexp' with outline style beginning-of-line anchor.
551 \(Ie, C-j, *or* C-m, for prefixes of hidden topics). This is properly
552 set when `allout-regexp' is produced by `set-allout-regexp', so
553 that (match-beginning 2) and (match-end 2) delimit the prefix.")
554 (make-variable-buffer-local 'allout-line-boundary-regexp)
555 ;;;_ = allout-bob-regexp
556 (defvar allout-bob-regexp ()
557 "Like `allout-line-boundary-regexp', for headers at beginning of buffer.
558 \(match-beginning 2) and \(match-end 2) delimit the prefix.")
559 (make-variable-buffer-local 'allout-bob-regexp)
560 ;;;_ = allout-header-subtraction
561 (defvar allout-header-subtraction (1- (length allout-header-prefix))
562 "Allout-header prefix length to subtract when computing topic depth.")
563 (make-variable-buffer-local 'allout-header-subtraction)
564 ;;;_ = allout-plain-bullets-string-len
565 (defvar allout-plain-bullets-string-len (length allout-plain-bullets-string)
566 "Length of `allout-plain-bullets-string', updated by `set-allout-regexp'.")
567 (make-variable-buffer-local 'allout-plain-bullets-string-len)
570 ;;;_ X allout-reset-header-lead (header-lead)
571 (defun allout-reset-header-lead (header-lead)
572 "*Reset the leading string used to identify topic headers."
573 (interactive "sNew lead string: ")
574 (setq allout-header-prefix header-lead)
575 (setq allout-header-subtraction (1- (length allout-header-prefix)))
576 (set-allout-regexp))
577 ;;;_ X allout-lead-with-comment-string (header-lead)
578 (defun allout-lead-with-comment-string (&optional header-lead)
579 "*Set the topic-header leading string to specified string.
581 Useful when for encapsulating outline structure in programming
582 language comments. Returns the leading string."
584 (interactive "P")
585 (if (not (stringp header-lead))
586 (setq header-lead (read-string
587 "String prefix for topic headers: ")))
588 (setq allout-reindent-bodies nil)
589 (allout-reset-header-lead header-lead)
590 header-lead)
591 ;;;_ > allout-infer-header-lead ()
592 (defun allout-infer-header-lead ()
593 "Determine appropriate `allout-header-prefix'.
595 Works according to settings of:
597 `comment-start'
598 `allout-header-prefix' (default)
599 `allout-use-mode-specific-leader'
600 and `allout-mode-leaders'.
602 Apply this via \(re)activation of `allout-mode', rather than
603 invoking it directly."
604 (let* ((use-leader (and (boundp 'allout-use-mode-specific-leader)
605 (if (or (stringp allout-use-mode-specific-leader)
606 (memq allout-use-mode-specific-leader
607 '(allout-mode-leaders
608 comment-start
609 t)))
610 allout-use-mode-specific-leader
611 ;; Oops - garbled value, equate with effect of 't:
612 t)))
613 (leader
614 (cond
615 ((not use-leader) nil)
616 ;; Use the explicitly designated leader:
617 ((stringp use-leader) use-leader)
618 (t (or (and (memq use-leader '(t allout-mode-leaders))
619 ;; Get it from outline mode leaders?
620 (cdr (assq major-mode allout-mode-leaders)))
621 ;; ... didn't get from allout-mode-leaders...
622 (and (memq use-leader '(t comment-start))
623 comment-start
624 ;; Use comment-start, maybe tripled, and with
625 ;; underscore:
626 (concat
627 (if (string= " "
628 (substring comment-start
629 (1- (length comment-start))))
630 ;; Use comment-start, sans trailing space:
631 (substring comment-start 0 -1)
632 (concat comment-start comment-start comment-start))
633 ;; ... and append underscore, whichever:
634 "_")))))))
635 (if (not leader)
637 (if (string= leader allout-header-prefix)
638 nil ; no change, nothing to do.
639 (setq allout-header-prefix leader)
640 allout-header-prefix))))
641 ;;;_ > allout-infer-body-reindent ()
642 (defun allout-infer-body-reindent ()
643 "Determine proper setting for `allout-reindent-bodies'.
645 Depends on default setting of `allout-reindent-bodies' \(which see)
646 and presence of setting for `comment-start', to tell whether the
647 file is programming code."
648 (if (and allout-reindent-bodies
649 comment-start
650 (not (eq 'force allout-reindent-bodies)))
651 (setq allout-reindent-bodies nil)))
652 ;;;_ > set-allout-regexp ()
653 (defun set-allout-regexp ()
654 "Generate proper topic-header regexp form for outline functions.
656 Works with respect to `allout-plain-bullets-string' and
657 `allout-distinctive-bullets-string'."
659 (interactive)
660 ;; Derive allout-bullets-string from user configured components:
661 (setq allout-bullets-string "")
662 (let ((strings (list 'allout-plain-bullets-string
663 'allout-distinctive-bullets-string
664 'allout-primary-bullet))
665 cur-string
666 cur-len
667 cur-char
668 cur-char-string
669 index
670 new-string)
671 (while strings
672 (setq new-string "") (setq index 0)
673 (setq cur-len (length (setq cur-string (symbol-value (car strings)))))
674 (while (< index cur-len)
675 (setq cur-char (aref cur-string index))
676 (setq allout-bullets-string
677 (concat allout-bullets-string
678 (cond
679 ; Single dash would denote a
680 ; sequence, repeated denotes
681 ; a dash:
682 ((eq cur-char ?-) "--")
683 ; literal close-square-bracket
684 ; doesn't work right in the
685 ; expr, exclude it:
686 ((eq cur-char ?\]) "")
687 (t (regexp-quote (char-to-string cur-char))))))
688 (setq index (1+ index)))
689 (setq strings (cdr strings)))
691 ;; Derive next for repeated use in allout-pending-bullet:
692 (setq allout-plain-bullets-string-len (length allout-plain-bullets-string))
693 (setq allout-header-subtraction (1- (length allout-header-prefix)))
694 ;; Produce the new allout-regexp:
695 (setq allout-regexp (concat "\\(\\"
696 allout-header-prefix
697 "[ \t]*["
698 allout-bullets-string
699 "]\\)\\|\\"
700 allout-primary-bullet
701 "+\\|\^l"))
702 (setq allout-line-boundary-regexp
703 (concat "\\([\n\r]\\)\\(" allout-regexp "\\)"))
704 (setq allout-bob-regexp
705 (concat "\\(\\`\\)\\(" allout-regexp "\\)"))
707 ;;;_ : Key bindings
708 ;;;_ = allout-mode-map
709 (defvar allout-mode-map nil "Keybindings for (allout) outline minor mode.")
710 ;;;_ > produce-allout-mode-map (keymap-alist &optional base-map)
711 (defun produce-allout-mode-map (keymap-list &optional base-map)
712 "Produce keymap for use as allout-mode-map, from KEYMAP-LIST.
714 Built on top of optional BASE-MAP, or empty sparse map if none specified.
715 See doc string for allout-keybindings-list for format of binding list."
716 (let ((map (or base-map (make-sparse-keymap)))
717 (pref (list allout-command-prefix)))
718 (mapcar (function
719 (lambda (cell)
720 (let ((add-pref (null (cdr (cdr cell))))
721 (key-suff (list (car cell))))
722 (apply 'define-key
723 (list map
724 (apply 'concat (if add-pref
725 (append pref key-suff)
726 key-suff))
727 (car (cdr cell)))))))
728 keymap-list)
729 map))
731 ;;;_ : Menu bar
732 (defvar allout-mode-exposure-menu)
733 (defvar allout-mode-editing-menu)
734 (defvar allout-mode-navigation-menu)
735 (defvar allout-mode-misc-menu)
736 (defun produce-allout-mode-menubar-entries ()
737 (require 'easymenu)
738 (easy-menu-define allout-mode-exposure-menu
739 allout-mode-map
740 "Allout outline exposure menu."
741 '("Exposure"
742 ["Show Entry" allout-show-current-entry t]
743 ["Show Children" allout-show-children t]
744 ["Show Subtree" allout-show-current-subtree t]
745 ["Hide Subtree" allout-hide-current-subtree t]
746 ["Hide Leaves" allout-hide-current-leaves t]
747 "----"
748 ["Show All" allout-show-all t]))
749 (easy-menu-define allout-mode-editing-menu
750 allout-mode-map
751 "Allout outline editing menu."
752 '("Headings"
753 ["Open Sibling" allout-open-sibtopic t]
754 ["Open Subtopic" allout-open-subtopic t]
755 ["Open Supertopic" allout-open-supertopic t]
756 "----"
757 ["Shift Topic In" allout-shift-in t]
758 ["Shift Topic Out" allout-shift-out t]
759 ["Rebullet Topic" allout-rebullet-topic t]
760 ["Rebullet Heading" allout-rebullet-current-heading t]
761 ["Number Siblings" allout-number-siblings t]))
762 (easy-menu-define allout-mode-navigation-menu
763 allout-mode-map
764 "Allout outline navigation menu."
765 '("Navigation"
766 ["Next Visible Heading" allout-next-visible-heading t]
767 ["Previous Visible Heading"
768 allout-previous-visible-heading t]
769 "----"
770 ["Up Level" allout-up-current-level t]
771 ["Forward Current Level" allout-forward-current-level t]
772 ["Backward Current Level"
773 allout-backward-current-level t]
774 "----"
775 ["Beginning of Entry"
776 allout-beginning-of-current-entry t]
777 ["End of Entry" allout-end-of-current-entry t]
778 ["End of Subtree" allout-end-of-current-subtree t]))
779 (easy-menu-define allout-mode-misc-menu
780 allout-mode-map
781 "Allout outlines miscellaneous bindings."
782 '("Misc"
783 ["Version" allout-version t]
784 "----"
785 ["Duplicate Exposed" allout-copy-exposed-to-buffer t]
786 ["Duplicate Exposed, numbered"
787 allout-flatten-exposed-to-buffer t]
788 ["Duplicate Exposed, indented"
789 allout-indented-exposed-to-buffer t]
790 "----"
791 ["Set Header Lead" allout-reset-header-lead t]
792 ["Set New Exposure" allout-expose-topic t])))
793 ;;;_ : Mode-Specific Variable Maintenance Utilities
794 ;;;_ = allout-mode-prior-settings
795 (defvar allout-mode-prior-settings nil
796 "Internal `allout-mode' use; settings to be resumed on mode deactivation.")
797 (make-variable-buffer-local 'allout-mode-prior-settings)
798 ;;;_ > allout-resumptions (name &optional value)
799 (defun allout-resumptions (name &optional value)
801 "Registers or resumes settings over `allout-mode' activation/deactivation.
803 First arg is NAME of variable affected. Optional second arg is list
804 containing allout-mode-specific VALUE to be imposed on named
805 variable, and to be registered. (It's a list so you can specify
806 registrations of null values.) If no value is specified, the
807 registered value is returned (encapsulated in the list, so the caller
808 can distinguish nil vs no value), and the registration is popped
809 from the list."
811 (let ((on-list (assq name allout-mode-prior-settings))
812 prior-capsule ; By `capsule' i mean a list
813 ; containing a value, so we can
814 ; distinguish nil from no value.
817 (if value
819 ;; Registering:
820 (progn
821 (if on-list
822 nil ; Already preserved prior value - don't mess with it.
823 ;; Register the old value, or nil if previously unbound:
824 (setq allout-mode-prior-settings
825 (cons (list name
826 (if (boundp name) (list (symbol-value name))))
827 allout-mode-prior-settings)))
828 ; And impose the new value, locally:
829 (progn (make-local-variable name)
830 (set name (car value))))
832 ;; Relinquishing:
833 (if (not on-list)
835 ;; Oops, not registered - leave it be:
838 ;; Some registration:
839 ; reestablish it:
840 (setq prior-capsule (car (cdr on-list)))
841 (if prior-capsule
842 (set name (car prior-capsule)) ; Some prior value - reestablish it.
843 (makunbound name)) ; Previously unbound - demolish var.
844 ; Remove registration:
845 (let (rebuild)
846 (while allout-mode-prior-settings
847 (if (not (eq (car allout-mode-prior-settings)
848 on-list))
849 (setq rebuild
850 (cons (car allout-mode-prior-settings)
851 rebuild)))
852 (setq allout-mode-prior-settings
853 (cdr allout-mode-prior-settings)))
854 (setq allout-mode-prior-settings rebuild)))))
856 ;;;_ : Mode-specific incidentals
857 ;;;_ = allout-during-write-cue nil
858 (defvar allout-during-write-cue nil
859 "Used to inhibit outline change-protection during file write.
861 See also `allout-post-command-business', `allout-write-file-hook',
862 `allout-before-change-protect', and `allout-post-command-business'
863 functions.")
864 ;;;_ = allout-pre-was-isearching nil
865 (defvar allout-pre-was-isearching nil
866 "Cue for isearch-dynamic-exposure mechanism, implemented in
867 allout-pre- and -post-command-hooks.")
868 (make-variable-buffer-local 'allout-pre-was-isearching)
869 ;;;_ = allout-isearch-prior-pos nil
870 (defvar allout-isearch-prior-pos nil
871 "Cue for isearch-dynamic-exposure tracking, used by `allout-isearch-expose'.")
872 (make-variable-buffer-local 'allout-isearch-prior-pos)
873 ;;;_ = allout-override-protect nil
874 (defvar allout-override-protect nil
875 "Used in `allout-mode' for regulate of concealed-text protection mechanism.
877 Allout outline mode regulates alteration of concealed text to protect
878 against inadvertent, unnoticed changes. This is for use by specific,
879 native outline functions to temporarily override that protection.
880 It's automatically reset to nil after every buffer modification.")
881 (make-variable-buffer-local 'allout-override-protect)
882 ;;;_ > allout-unprotected (expr)
883 (defmacro allout-unprotected (expression)
884 "Evaluate EXPRESSION with `allout-override-protect' let-bound to t."
885 `(let ((allout-override-protect t))
886 ,expression))
887 ;;;_ = allout-undo-aggregation
888 (defvar allout-undo-aggregation 30
889 "Amount of successive self-insert actions to bunch together per undo.
891 This is purely a kludge variable, regulating the compensation for a bug in
892 the way that `before-change-functions' and undo interact.")
893 (make-variable-buffer-local 'allout-undo-aggregation)
894 ;;;_ = file-var-bug hack
895 (defvar allout-v18/19-file-var-hack nil
896 "Horrible hack used to prevent invalid multiple triggering of outline
897 mode from prop-line file-var activation. Used by `allout-mode' function
898 to track repeats.")
899 ;;;_ > allout-write-file-hook ()
900 (defun allout-write-file-hook ()
901 "In `allout-mode', run as a `write-contents-functions' activity.
903 Currently just sets `allout-during-write-cue', so outline change-protection
904 knows to keep inactive during file write."
905 (setq allout-during-write-cue t)
906 nil)
908 ;;;_ #2 Mode activation
909 ;;;_ = allout-mode
910 (defvar allout-mode () "Allout outline mode minor-mode flag.")
911 (make-variable-buffer-local 'allout-mode)
912 ;;;_ > allout-mode-p ()
913 (defmacro allout-mode-p ()
914 "Return t if `allout-mode' is active in current buffer."
915 'allout-mode)
916 ;;;_ = allout-explicitly-deactivated
917 (defvar allout-explicitly-deactivated nil
918 "Non-nil if `allout-mode' was last deliberately deactivated.
919 So `allout-post-command-business' should not reactivate it...")
920 (make-variable-buffer-local 'allout-explicitly-deactivated)
921 ;;;_ > allout-init (&optional mode)
922 ;;;###autoload
923 (defun allout-init (&optional mode)
924 "Prime `allout-mode' to enable/disable auto-activation, wrt `allout-layout'.
926 MODE is one of the following symbols:
928 - nil \(or no argument) deactivate auto-activation/layout;
929 - `activate', enable auto-activation only;
930 - `ask', enable auto-activation, and enable auto-layout but with
931 confirmation for layout operation solicited from user each time;
932 - `report', just report and return the current auto-activation state;
933 - anything else \(eg, t) for auto-activation and auto-layout, without
934 any confirmation check.
936 Use this function to setup your Emacs session for automatic activation
937 of allout outline mode, contingent to the buffer-specific setting of
938 the `allout-layout' variable. (See `allout-layout' and
939 `allout-expose-topic' docstrings for more details on auto layout).
941 `allout-init' works by setting up (or removing)
942 `allout-find-file-hook' in `find-file-hook', and giving
943 `allout-auto-activation' a suitable setting.
945 To prime your Emacs session for full auto-outline operation, include
946 the following two lines in your Emacs init file:
948 \(require 'allout)
949 \(allout-init t)"
951 (interactive
952 (let ((m (completing-read
953 (concat "Select outline auto setup mode "
954 "(empty for report, ? for options) ")
955 '(("nil")("full")("activate")("deactivate")
956 ("ask") ("report") (""))
958 t)))
959 (if (string= m "") 'report
960 (intern-soft m))))
961 (let
962 ;; convenience aliases, for consistent ref to respective vars:
963 ((hook 'allout-find-file-hook)
964 (curr-mode 'allout-auto-activation))
966 (cond ((not mode)
967 (setq find-file-hook (delq hook find-file-hook))
968 (if (interactive-p)
969 (message "Allout outline mode auto-activation inhibited.")))
970 ((eq mode 'report)
971 (if (memq hook find-file-hook)
972 ;; Just punt and use the reports from each of the modes:
973 (allout-init (symbol-value curr-mode))
974 (allout-init nil)
975 (message "Allout outline mode auto-activation inhibited.")))
976 (t (add-hook 'find-file-hook hook)
977 (set curr-mode ; `set', not `setq'!
978 (cond ((eq mode 'activate)
979 (message
980 "Outline mode auto-activation enabled.")
981 'activate)
982 ((eq mode 'report)
983 ;; Return the current mode setting:
984 (allout-init mode))
985 ((eq mode 'ask)
986 (message
987 (concat "Outline mode auto-activation and "
988 "-layout \(upon confirmation) enabled."))
989 'ask)
990 ((message
991 "Outline mode auto-activation and -layout enabled.")
992 'full)))))))
994 ;;;_ > allout-setup-menubar ()
995 (defun allout-setup-menubar ()
996 "Populate the current buffer's menubar with `allout-mode' stuff."
997 (let ((menus (list allout-mode-exposure-menu
998 allout-mode-editing-menu
999 allout-mode-navigation-menu
1000 allout-mode-misc-menu))
1001 cur)
1002 (while menus
1003 (setq cur (car menus)
1004 menus (cdr menus))
1005 (easy-menu-add cur))))
1006 ;;;_ > allout-mode (&optional toggle)
1007 ;;;_ : Defun:
1008 (defun allout-mode (&optional toggle)
1009 ;;;_ . Doc string:
1010 "Toggle minor mode for controlling exposure and editing of text outlines.
1012 Optional arg forces mode to re-initialize iff arg is positive num or
1013 symbol. Allout outline mode always runs as a minor mode.
1015 Allout outline mode provides extensive outline oriented formatting and
1016 manipulation. It enables structural editing of outlines, as well as
1017 navigation and exposure. It also is specifically aimed at
1018 accommodating syntax-sensitive text like programming languages. \(For
1019 an example, see the allout code itself, which is organized as an allout
1020 outline.)
1022 In addition to outline navigation and exposure, allout includes:
1024 - topic-oriented repositioning, cut, and paste
1025 - integral outline exposure-layout
1026 - incremental search with dynamic exposure and reconcealment of hidden text
1027 - automatic topic-number maintenance
1028 - \"Hot-spot\" operation, for single-keystroke maneuvering and
1029 exposure control. \(See the allout-mode docstring.)
1031 and many other features.
1033 Below is a description of the bindings, and then explanation of
1034 special `allout-mode' features and terminology. See also the outline
1035 menubar additions for quick reference to many of the features, and see
1036 the docstring of the function `allout-init' for instructions on
1037 priming your Emacs session for automatic activation of `allout-mode'.
1040 The bindings are dictated by the `allout-keybindings-list' and
1041 `allout-command-prefix' variables.
1043 Navigation: Exposure Control:
1044 ---------- ----------------
1045 C-c C-n allout-next-visible-heading | C-c C-h allout-hide-current-subtree
1046 C-c C-p allout-previous-visible-heading | C-c C-i allout-show-children
1047 C-c C-u allout-up-current-level | C-c C-s allout-show-current-subtree
1048 C-c C-f allout-forward-current-level | C-c C-o allout-show-current-entry
1049 C-c C-b allout-backward-current-level | ^U C-c C-s allout-show-all
1050 C-c C-e allout-end-of-current-entry | allout-hide-current-leaves
1051 C-c C-a allout-beginning-of-current-entry, alternately, goes to hot-spot
1053 Topic Header Production:
1054 -----------------------
1055 C-c<SP> allout-open-sibtopic Create a new sibling after current topic.
1056 C-c . allout-open-subtopic ... an offspring of current topic.
1057 C-c , allout-open-supertopic ... a sibling of the current topic's parent.
1059 Topic Level and Prefix Adjustment:
1060 ---------------------------------
1061 C-c > allout-shift-in Shift current topic and all offspring deeper.
1062 C-c < allout-shift-out ... less deep.
1063 C-c<CR> allout-rebullet-topic Reconcile bullets of topic and its offspring
1064 - distinctive bullets are not changed, others
1065 alternated according to nesting depth.
1066 C-c * allout-rebullet-current-heading Prompt for alternate bullet for
1067 current topic.
1068 C-c # allout-number-siblings Number bullets of topic and siblings - the
1069 offspring are not affected. With repeat
1070 count, revoke numbering.
1072 Topic-oriented Killing and Yanking:
1073 ----------------------------------
1074 C-c C-k allout-kill-topic Kill current topic, including offspring.
1075 C-k allout-kill-line Like kill-line, but reconciles numbering, etc.
1076 C-y allout-yank Yank, adjusting depth of yanked topic to
1077 depth of heading if yanking into bare topic
1078 heading (ie, prefix sans text).
1079 M-y allout-yank-pop Is to allout-yank as yank-pop is to yank
1081 Misc commands:
1082 -------------
1083 M-x outlineify-sticky Activate outline mode for current buffer,
1084 and establish a default file-var setting
1085 for `allout-layout'.
1086 C-c C-SPC allout-mark-topic
1087 C-c = c allout-copy-exposed-to-buffer
1088 Duplicate outline, sans concealed text, to
1089 buffer with name derived from derived from
1090 that of current buffer - \"*XXX exposed*\".
1091 C-c = p allout-flatten-exposed-to-buffer
1092 Like above 'copy-exposed', but convert topic
1093 prefixes to section.subsection... numeric
1094 format.
1095 ESC ESC (allout-init t) Setup Emacs session for outline mode
1096 auto-activation.
1098 HOT-SPOT Operation
1100 Hot-spot operation provides a means for easy, single-keystroke outline
1101 navigation and exposure control.
1103 \\<allout-mode-map>
1104 When the text cursor is positioned directly on the bullet character of
1105 a topic, regular characters (a to z) invoke the commands of the
1106 corresponding allout-mode keymap control chars. For example, \"f\"
1107 would invoke the command typically bound to \"C-c C-f\"
1108 \(\\[allout-forward-current-level] `allout-forward-current-level').
1110 Thus, by positioning the cursor on a topic bullet, you can execute
1111 the outline navigation and manipulation commands with a single
1112 keystroke. Non-literal chars never get this special translation, so
1113 you can use them to get away from the hot-spot, and back to normal
1114 operation.
1116 Note that the command `allout-beginning-of-current-entry' \(\\[allout-beginning-of-current-entry]\)
1117 will move to the hot-spot when the cursor is already located at the
1118 beginning of the current entry, so you can simply hit \\[allout-beginning-of-current-entry]
1119 twice in a row to get to the hot-spot.
1121 Terminology
1123 Topic hierarchy constituents - TOPICS and SUBTOPICS:
1125 TOPIC: A basic, coherent component of an Emacs outline. It can
1126 contain other topics, and it can be subsumed by other topics,
1127 CURRENT topic:
1128 The visible topic most immediately containing the cursor.
1129 DEPTH: The degree of nesting of a topic; it increases with
1130 containment. Also called the:
1131 LEVEL: The same as DEPTH.
1133 ANCESTORS:
1134 The topics that contain a topic.
1135 PARENT: A topic's immediate ancestor. It has a depth one less than
1136 the topic.
1137 OFFSPRING:
1138 The topics contained by a topic;
1139 SUBTOPIC:
1140 An immediate offspring of a topic;
1141 CHILDREN:
1142 The immediate offspring of a topic.
1143 SIBLINGS:
1144 Topics having the same parent and depth.
1146 Topic text constituents:
1148 HEADER: The first line of a topic, include the topic PREFIX and header
1149 text.
1150 PREFIX: The leading text of a topic which distinguishes it from
1151 normal text. It has a strict form, which consists of a
1152 prefix-lead string, padding, and a bullet. The bullet may be
1153 followed by a number, indicating the ordinal number of the
1154 topic among its siblings, a space, and then the header text.
1156 The relative length of the PREFIX determines the nesting depth
1157 of the topic.
1158 PREFIX-LEAD:
1159 The string at the beginning of a topic prefix, normally a `.'.
1160 It can be customized by changing the setting of
1161 `allout-header-prefix' and then reinitializing `allout-mode'.
1163 By setting the prefix-lead to the comment-string of a
1164 programming language, you can embed outline structuring in
1165 program code without interfering with the language processing
1166 of that code. See `allout-use-mode-specific-leader'
1167 docstring for more detail.
1168 PREFIX-PADDING:
1169 Spaces or asterisks which separate the prefix-lead and the
1170 bullet, according to the depth of the topic.
1171 BULLET: A character at the end of the topic prefix, it must be one of
1172 the characters listed on `allout-plain-bullets-string' or
1173 `allout-distinctive-bullets-string'. (See the documentation
1174 for these variables for more details.) The default choice of
1175 bullet when generating varies in a cycle with the depth of the
1176 topic.
1177 ENTRY: The text contained in a topic before any offspring.
1178 BODY: Same as ENTRY.
1181 EXPOSURE:
1182 The state of a topic which determines the on-screen visibility
1183 of its offspring and contained text.
1184 CONCEALED:
1185 Topics and entry text whose display is inhibited. Contiguous
1186 units of concealed text is represented by `...' ellipses.
1187 (Ref the `selective-display' var.)
1189 Concealed topics are effectively collapsed within an ancestor.
1190 CLOSED: A topic whose immediate offspring and body-text is concealed.
1191 OPEN: A topic that is not closed, though its offspring or body may be."
1192 ;;;_ . Code
1193 (interactive "P")
1195 (let* ((active (and (not (equal major-mode 'outline))
1196 (allout-mode-p)))
1197 ; Massage universal-arg `toggle' val:
1198 (toggle (and toggle
1199 (or (and (listp toggle)(car toggle))
1200 toggle)))
1201 ; Activation specifically demanded?
1202 (explicit-activation (or
1204 (and toggle
1205 (or (symbolp toggle)
1206 (and (natnump toggle)
1207 (not (zerop toggle)))))))
1208 ;; allout-mode already called once during this complex command?
1209 (same-complex-command (eq allout-v18/19-file-var-hack
1210 (car command-history)))
1211 do-layout
1214 ; See comments below re v19.18,.19 bug.
1215 (setq allout-v18/19-file-var-hack (car command-history))
1217 (cond
1219 ;; Provision for v19.18, 19.19 bug -
1220 ;; Emacs v 19.18, 19.19 file-var code invokes prop-line-designated
1221 ;; modes twice when file is visited. We have to avoid toggling mode
1222 ;; off on second invocation, so we detect it as best we can, and
1223 ;; skip everything.
1224 ((and same-complex-command ; Still in same complex command
1225 ; as last time `allout-mode' invoked.
1226 active ; Already activated.
1227 (not explicit-activation) ; Prop-line file-vars don't have args.
1228 (string-match "^19.1[89]" ; Bug only known to be in v19.18 and
1229 emacs-version)); 19.19.
1232 ;; Deactivation:
1233 ((and (not explicit-activation)
1234 (or active toggle))
1235 ; Activation not explicitly
1236 ; requested, and either in
1237 ; active state or *de*activation
1238 ; specifically requested:
1239 (setq allout-explicitly-deactivated t)
1241 (if allout-old-style-prefixes
1242 (progn
1243 (allout-resumptions 'allout-primary-bullet)
1244 (allout-resumptions 'allout-old-style-prefixes)))
1245 (allout-resumptions 'selective-display)
1246 (if (and (boundp 'before-change-functions) before-change-functions)
1247 (allout-resumptions 'before-change-functions))
1248 (setq write-contents-functions
1249 (delq 'allout-write-file-hook
1250 write-contents-functions))
1251 (allout-resumptions 'paragraph-start)
1252 (allout-resumptions 'paragraph-separate)
1253 (allout-resumptions (if (string-match "^18" emacs-version)
1254 'auto-fill-hook
1255 'auto-fill-function))
1256 (allout-resumptions 'allout-former-auto-filler)
1257 (setq allout-mode nil))
1259 ;; Activation:
1260 ((not active)
1261 (setq allout-explicitly-deactivated nil)
1262 (if allout-old-style-prefixes
1263 (progn ; Inhibit all the fancy formatting:
1264 (allout-resumptions 'allout-primary-bullet '("*"))
1265 (allout-resumptions 'allout-old-style-prefixes '(()))))
1267 (allout-infer-header-lead)
1268 (allout-infer-body-reindent)
1270 (set-allout-regexp)
1272 ; Produce map from current version
1273 ; of allout-keybindings-list:
1274 (if (boundp 'minor-mode-map-alist)
1276 (progn ; V19, and maybe lucid and
1277 ; epoch, minor-mode key bindings:
1278 (setq allout-mode-map
1279 (produce-allout-mode-map allout-keybindings-list))
1280 (produce-allout-mode-menubar-entries)
1281 (fset 'allout-mode-map allout-mode-map)
1282 ; Include on minor-mode-map-alist,
1283 ; if not already there:
1284 (if (not (member '(allout-mode . allout-mode-map)
1285 minor-mode-map-alist))
1286 (setq minor-mode-map-alist
1287 (cons '(allout-mode . allout-mode-map)
1288 minor-mode-map-alist))))
1290 ; and add them:
1291 (use-local-map (produce-allout-mode-map allout-keybindings-list
1292 (current-local-map)))
1295 ; selective-display is the
1296 ; Emacs conditional exposure
1297 ; mechanism:
1298 (allout-resumptions 'selective-display '(t))
1299 (if allout-inhibit-protection
1301 (allout-resumptions 'before-change-functions
1302 '(allout-before-change-protect)))
1303 (add-hook 'pre-command-hook 'allout-pre-command-business)
1304 (add-hook 'post-command-hook 'allout-post-command-business)
1305 ; Temporarily set by any outline
1306 ; functions that can be trusted to
1307 ; deal properly with concealed text.
1308 (add-hook 'write-contents-functions 'allout-write-file-hook)
1309 ; Custom auto-fill func, to support
1310 ; respect for topic headline,
1311 ; hanging-indents, etc:
1312 (let* ((fill-func-var (if (string-match "^18" emacs-version)
1313 'auto-fill-hook
1314 'auto-fill-function))
1315 (fill-func (symbol-value fill-func-var)))
1316 ;; Register prevailing fill func for use by allout-auto-fill:
1317 (allout-resumptions 'allout-former-auto-filler (list fill-func))
1318 ;; Register allout-auto-fill to be used if filling is active:
1319 (allout-resumptions fill-func-var '(allout-auto-fill)))
1320 ;; Paragraphs are broken by topic headlines.
1321 (make-local-variable 'paragraph-start)
1322 (allout-resumptions 'paragraph-start
1323 (list (concat paragraph-start "\\|^\\("
1324 allout-regexp "\\)")))
1325 (make-local-variable 'paragraph-separate)
1326 (allout-resumptions 'paragraph-separate
1327 (list (concat paragraph-separate "\\|^\\("
1328 allout-regexp "\\)")))
1330 (or (assq 'allout-mode minor-mode-alist)
1331 (setq minor-mode-alist
1332 (cons '(allout-mode " Allout") minor-mode-alist)))
1334 (allout-setup-menubar)
1336 (if allout-layout
1337 (setq do-layout t))
1339 (if allout-isearch-dynamic-expose
1340 (allout-enwrap-isearch))
1342 (run-hooks 'allout-mode-hook)
1343 (setq allout-mode t))
1345 ;; Reactivation:
1346 ((setq do-layout t)
1347 (allout-infer-body-reindent))
1348 ) ; cond
1350 (if (and do-layout
1351 allout-auto-activation
1352 (listp allout-layout)
1353 (and (not (eq allout-auto-activation 'activate))
1354 (if (eq allout-auto-activation 'ask)
1355 (if (y-or-n-p (format "Expose %s with layout '%s'? "
1356 (buffer-name)
1357 allout-layout))
1359 (message "Skipped %s layout." (buffer-name))
1360 nil)
1361 t)))
1362 (save-excursion
1363 (message "Adjusting '%s' exposure..." (buffer-name))
1364 (goto-char 0)
1365 (allout-this-or-next-heading)
1366 (condition-case err
1367 (progn
1368 (apply 'allout-expose-topic (list allout-layout))
1369 (message "Adjusting '%s' exposure... done." (buffer-name)))
1370 ;; Problem applying exposure - notify user, but don't
1371 ;; interrupt, eg, file visit:
1372 (error (message "%s" (car (cdr err)))
1373 (sit-for 1)))))
1374 allout-mode
1375 ) ; let*
1376 ) ; defun
1377 ;;;_ > allout-minor-mode
1378 ;;; XXX released verion doesn't do this?
1379 (defalias 'allout-minor-mode 'allout-mode)
1381 ;;;_ #3 Internal Position State-Tracking - "allout-recent-*" funcs
1382 ;;; All the basic outline functions that directly do string matches to
1383 ;;; evaluate heading prefix location set the variables
1384 ;;; `allout-recent-prefix-beginning' and `allout-recent-prefix-end'
1385 ;;; when successful. Functions starting with `allout-recent-' all
1386 ;;; use this state, providing the means to avoid redundant searches
1387 ;;; for just-established data. This optimization can provide
1388 ;;; significant speed improvement, but it must be employed carefully.
1389 ;;;_ = allout-recent-prefix-beginning
1390 (defvar allout-recent-prefix-beginning 0
1391 "Buffer point of the start of the last topic prefix encountered.")
1392 (make-variable-buffer-local 'allout-recent-prefix-beginning)
1393 ;;;_ = allout-recent-prefix-end
1394 (defvar allout-recent-prefix-end 0
1395 "Buffer point of the end of the last topic prefix encountered.")
1396 (make-variable-buffer-local 'allout-recent-prefix-end)
1397 ;;;_ = allout-recent-end-of-subtree
1398 (defvar allout-recent-end-of-subtree 0
1399 "Buffer point last returned by `allout-end-of-current-subtree'.")
1400 (make-variable-buffer-local 'allout-recent-end-of-subtree)
1401 ;;;_ > allout-prefix-data (beg end)
1402 (defmacro allout-prefix-data (beginning end)
1403 "Register allout-prefix state data - BEGINNING and END of prefix.
1405 For reference by `allout-recent' funcs. Returns BEGINNING."
1406 `(setq allout-recent-prefix-end ,end
1407 allout-recent-prefix-beginning ,beginning))
1408 ;;;_ > allout-recent-depth ()
1409 (defmacro allout-recent-depth ()
1410 "Return depth of last heading encountered by an outline maneuvering function.
1412 All outline functions which directly do string matches to assess
1413 headings set the variables `allout-recent-prefix-beginning' and
1414 `allout-recent-prefix-end' if successful. This function uses those settings
1415 to return the current depth."
1417 '(max 1 (- allout-recent-prefix-end
1418 allout-recent-prefix-beginning
1419 allout-header-subtraction)))
1420 ;;;_ > allout-recent-prefix ()
1421 (defmacro allout-recent-prefix ()
1422 "Like `allout-recent-depth', but returns text of last encountered prefix.
1424 All outline functions which directly do string matches to assess
1425 headings set the variables `allout-recent-prefix-beginning' and
1426 `allout-recent-prefix-end' if successful. This function uses those settings
1427 to return the current depth."
1428 '(buffer-substring allout-recent-prefix-beginning
1429 allout-recent-prefix-end))
1430 ;;;_ > allout-recent-bullet ()
1431 (defmacro allout-recent-bullet ()
1432 "Like allout-recent-prefix, but returns bullet of last encountered prefix.
1434 All outline functions which directly do string matches to assess
1435 headings set the variables `allout-recent-prefix-beginning' and
1436 `allout-recent-prefix-end' if successful. This function uses those settings
1437 to return the current depth of the most recently matched topic."
1438 '(buffer-substring (1- allout-recent-prefix-end)
1439 allout-recent-prefix-end))
1441 ;;;_ #4 Navigation
1443 ;;;_ - Position Assessment
1444 ;;;_ : Location Predicates
1445 ;;;_ > allout-on-current-heading-p ()
1446 (defun allout-on-current-heading-p ()
1447 "Return non-nil if point is on current visible topics' header line.
1449 Actually, returns prefix beginning point."
1450 (save-excursion
1451 (beginning-of-line)
1452 (and (looking-at allout-regexp)
1453 (allout-prefix-data (match-beginning 0) (match-end 0)))))
1454 ;;;_ > allout-on-heading-p ()
1455 (defalias 'allout-on-heading-p 'allout-on-current-heading-p)
1456 ;;;_ > allout-e-o-prefix-p ()
1457 (defun allout-e-o-prefix-p ()
1458 "True if point is located where current topic prefix ends, heading begins."
1459 (and (save-excursion (beginning-of-line)
1460 (looking-at allout-regexp))
1461 (= (point)(save-excursion (allout-end-of-prefix)(point)))))
1462 ;;;_ > allout-hidden-p ()
1463 (defmacro allout-hidden-p ()
1464 "True if point is in hidden text."
1465 '(save-excursion
1466 (and (re-search-backward "[\n\r]" () t)
1467 (= ?\r (following-char)))))
1468 ;;;_ > allout-visible-p ()
1469 (defmacro allout-visible-p ()
1470 "True if point is not in hidden text."
1471 (interactive)
1472 '(not (allout-hidden-p)))
1473 ;;;_ : Location attributes
1474 ;;;_ > allout-depth ()
1475 (defsubst allout-depth ()
1476 "Like `allout-current-depth', but respects hidden as well as visible topics."
1477 (save-excursion
1478 (if (allout-goto-prefix)
1479 (allout-recent-depth)
1480 (progn
1481 ;; Oops, no prefix, zero prefix data:
1482 (allout-prefix-data (point)(point))
1483 ;; ... and return 0:
1484 0))))
1485 ;;;_ > allout-current-depth ()
1486 (defmacro allout-current-depth ()
1487 "Return nesting depth of visible topic most immediately containing point."
1488 '(save-excursion
1489 (if (allout-back-to-current-heading)
1490 (max 1
1491 (- allout-recent-prefix-end
1492 allout-recent-prefix-beginning
1493 allout-header-subtraction))
1494 0)))
1495 ;;;_ > allout-get-current-prefix ()
1496 (defun allout-get-current-prefix ()
1497 "Topic prefix of the current topic."
1498 (save-excursion
1499 (if (allout-goto-prefix)
1500 (allout-recent-prefix))))
1501 ;;;_ > allout-get-bullet ()
1502 (defun allout-get-bullet ()
1503 "Return bullet of containing topic (visible or not)."
1504 (save-excursion
1505 (and (allout-goto-prefix)
1506 (allout-recent-bullet))))
1507 ;;;_ > allout-current-bullet ()
1508 (defun allout-current-bullet ()
1509 "Return bullet of current (visible) topic heading, or none if none found."
1510 (condition-case err
1511 (save-excursion
1512 (allout-back-to-current-heading)
1513 (buffer-substring (- allout-recent-prefix-end 1)
1514 allout-recent-prefix-end))
1515 ;; Quick and dirty provision, ostensibly for missing bullet:
1516 ('args-out-of-range nil))
1518 ;;;_ > allout-get-prefix-bullet (prefix)
1519 (defun allout-get-prefix-bullet (prefix)
1520 "Return the bullet of the header prefix string PREFIX."
1521 ;; Doesn't make sense if we're old-style prefixes, but this just
1522 ;; oughtn't be called then, so forget about it...
1523 (if (string-match allout-regexp prefix)
1524 (substring prefix (1- (match-end 0)) (match-end 0))))
1525 ;;;_ > allout-sibling-index (&optional depth)
1526 (defun allout-sibling-index (&optional depth)
1527 "Item number of this prospective topic among its siblings.
1529 If optional arg DEPTH is greater than current depth, then we're
1530 opening a new level, and return 0.
1532 If less than this depth, ascend to that depth and count..."
1534 (save-excursion
1535 (cond ((and depth (<= depth 0) 0))
1536 ((or (not depth) (= depth (allout-depth)))
1537 (let ((index 1))
1538 (while (allout-previous-sibling (allout-recent-depth) nil)
1539 (setq index (1+ index)))
1540 index))
1541 ((< depth (allout-recent-depth))
1542 (allout-ascend-to-depth depth)
1543 (allout-sibling-index))
1544 (0))))
1545 ;;;_ > allout-topic-flat-index ()
1546 (defun allout-topic-flat-index ()
1547 "Return a list indicating point's numeric section.subsect.subsubsect...
1548 Outermost is first."
1549 (let* ((depth (allout-depth))
1550 (next-index (allout-sibling-index depth))
1551 (rev-sibls nil))
1552 (while (> next-index 0)
1553 (setq rev-sibls (cons next-index rev-sibls))
1554 (setq depth (1- depth))
1555 (setq next-index (allout-sibling-index depth)))
1556 rev-sibls)
1559 ;;;_ - Navigation macros
1560 ;;;_ > allout-next-heading ()
1561 (defsubst allout-next-heading ()
1562 "Move to the heading for the topic \(possibly invisible) before this one.
1564 Returns the location of the heading, or nil if none found."
1566 (if (and (bobp) (not (eobp)))
1567 (forward-char 1))
1569 (if (re-search-forward allout-line-boundary-regexp nil 0)
1570 (allout-prefix-data ; Got valid location state - set vars:
1571 (goto-char (or (match-beginning 2)
1572 allout-recent-prefix-beginning))
1573 (or (match-end 2) allout-recent-prefix-end))))
1574 ;;;_ : allout-this-or-next-heading
1575 (defun allout-this-or-next-heading ()
1576 "Position cursor on current or next heading."
1577 ;; A throwaway non-macro that is defined after allout-next-heading
1578 ;; and usable by allout-mode.
1579 (if (not (allout-goto-prefix)) (allout-next-heading)))
1580 ;;;_ > allout-previous-heading ()
1581 (defmacro allout-previous-heading ()
1582 "Move to the prior \(possibly invisible) heading line.
1584 Return the location of the beginning of the heading, or nil if not found."
1586 '(if (bobp)
1588 (allout-goto-prefix)
1590 ;; searches are unbounded and return nil if failed:
1591 (or (re-search-backward allout-line-boundary-regexp nil 0)
1592 (looking-at allout-bob-regexp))
1593 (progn ; Got valid location state - set vars:
1594 (allout-prefix-data
1595 (goto-char (or (match-beginning 2)
1596 allout-recent-prefix-beginning))
1597 (or (match-end 2) allout-recent-prefix-end))))))
1599 ;;;_ - Subtree Charting
1600 ;;;_ " These routines either produce or assess charts, which are
1601 ;;; nested lists of the locations of topics within a subtree.
1603 ;;; Use of charts enables efficient navigation of subtrees, by
1604 ;;; requiring only a single regexp-search based traversal, to scope
1605 ;;; out the subtopic locations. The chart then serves as the basis
1606 ;;; for assessment or adjustment of the subtree, without redundant
1607 ;;; traversal of the structure.
1609 ;;;_ > allout-chart-subtree (&optional levels orig-depth prev-depth)
1610 (defun allout-chart-subtree (&optional levels orig-depth prev-depth)
1611 "Produce a location \"chart\" of subtopics of the containing topic.
1613 Optional argument LEVELS specifies the depth \(relative to start
1614 depth) for the chart.
1616 Charts are used to capture outline structure, so that outline altering
1617 routines need assess the structure only once, and then use the chart
1618 for their elaborate manipulations.
1620 Topics are entered in the chart so the last one is at the car.
1621 The entry for each topic consists of an integer indicating the point
1622 at the beginning of the topic. Charts for offspring consists of a
1623 list containing, recursively, the charts for the respective subtopics.
1624 The chart for a topics' offspring precedes the entry for the topic
1625 itself.
1627 \(fn &optional LEVELS)"
1629 ;; The other function parameters are for internal recursion, and should
1630 ;; not be specified by external callers. ORIG-DEPTH is depth of topic at
1631 ;; starting point, and PREV-DEPTH is depth of prior topic."
1633 (let ((original (not orig-depth)) ; `orig-depth' set only in recursion.
1634 chart curr-depth)
1636 (if original ; Just starting?
1637 ; Register initial settings and
1638 ; position to first offspring:
1639 (progn (setq orig-depth (allout-depth))
1640 (or prev-depth (setq prev-depth (1+ orig-depth)))
1641 (allout-next-heading)))
1643 ;; Loop over the current levels' siblings. Besides being more
1644 ;; efficient than tail-recursing over a level, it avoids exceeding
1645 ;; the typically quite constrained Emacs max-lisp-eval-depth.
1647 ;; Probably would speed things up to implement loop-based stack
1648 ;; operation rather than recursing for lower levels. Bah.
1650 (while (and (not (eobp))
1651 ; Still within original topic?
1652 (< orig-depth (setq curr-depth (allout-recent-depth)))
1653 (cond ((= prev-depth curr-depth)
1654 ;; Register this one and move on:
1655 (setq chart (cons (point) chart))
1656 (if (and levels (<= levels 1))
1657 ;; At depth limit - skip sublevels:
1658 (or (allout-next-sibling curr-depth)
1659 ;; or no more siblings - proceed to
1660 ;; next heading at lesser depth:
1661 (while (and (<= curr-depth
1662 (allout-recent-depth))
1663 (allout-next-heading))))
1664 (allout-next-heading)))
1666 ((and (< prev-depth curr-depth)
1667 (or (not levels)
1668 (> levels 0)))
1669 ;; Recurse on deeper level of curr topic:
1670 (setq chart
1671 (cons (allout-chart-subtree (and levels
1672 (1- levels))
1673 orig-depth
1674 curr-depth)
1675 chart))
1676 ;; ... then continue with this one.
1679 ;; ... else nil if we've ascended back to prev-depth.
1683 (if original ; We're at the last sibling on
1684 ; the original level. Position
1685 ; to the end of it:
1686 (progn (and (not (eobp)) (forward-char -1))
1687 (and (memq (preceding-char) '(?\n ?\r))
1688 (memq (aref (buffer-substring (max 1 (- (point) 3))
1689 (point))
1691 '(?\n ?\r))
1692 (forward-char -1))
1693 (setq allout-recent-end-of-subtree (point))))
1695 chart ; (nreverse chart) not necessary,
1696 ; and maybe not preferable.
1698 ;;;_ > allout-chart-siblings (&optional start end)
1699 (defun allout-chart-siblings (&optional start end)
1700 "Produce a list of locations of this and succeeding sibling topics.
1701 Effectively a top-level chart of siblings. See `allout-chart-subtree'
1702 for an explanation of charts."
1703 (save-excursion
1704 (if (allout-goto-prefix)
1705 (let ((chart (list (point))))
1706 (while (allout-next-sibling)
1707 (setq chart (cons (point) chart)))
1708 (if chart (setq chart (nreverse chart)))))))
1709 ;;;_ > allout-chart-to-reveal (chart depth)
1710 (defun allout-chart-to-reveal (chart depth)
1712 "Return a flat list of hidden points in subtree CHART, up to DEPTH.
1714 Note that point can be left at any of the points on chart, or at the
1715 start point."
1717 (let (result here)
1718 (while (and (or (eq depth t) (> depth 0))
1719 chart)
1720 (setq here (car chart))
1721 (if (listp here)
1722 (let ((further (allout-chart-to-reveal here (or (eq depth t)
1723 (1- depth)))))
1724 ;; We're on the start of a subtree - recurse with it, if there's
1725 ;; more depth to go:
1726 (if further (setq result (append further result)))
1727 (setq chart (cdr chart)))
1728 (goto-char here)
1729 (if (= (preceding-char) ?\r)
1730 (setq result (cons here result)))
1731 (setq chart (cdr chart))))
1732 result))
1733 ;;;_ X allout-chart-spec (chart spec &optional exposing)
1734 ;; (defun allout-chart-spec (chart spec &optional exposing)
1735 ;; "Not yet \(if ever) implemented.
1737 ;; Produce exposure directives given topic/subtree CHART and an exposure SPEC.
1739 ;; Exposure spec indicates the locations to be exposed and the prescribed
1740 ;; exposure status. Optional arg EXPOSING is an integer, with 0
1741 ;; indicating pending concealment, anything higher indicating depth to
1742 ;; which subtopic headers should be exposed, and negative numbers
1743 ;; indicating (negative of) the depth to which subtopic headers and
1744 ;; bodies should be exposed.
1746 ;; The produced list can have two types of entries. Bare numbers
1747 ;; indicate points in the buffer where topic headers that should be
1748 ;; exposed reside.
1750 ;; - bare negative numbers indicates that the topic starting at the
1751 ;; point which is the negative of the number should be opened,
1752 ;; including their entries.
1753 ;; - bare positive values indicate that this topic header should be
1754 ;; opened.
1755 ;; - Lists signify the beginning and end points of regions that should
1756 ;; be flagged, and the flag to employ. (For concealment: `\(\?r\)', and
1757 ;; exposure:"
1758 ;; (while spec
1759 ;; (cond ((listp spec)
1760 ;; )
1761 ;; )
1762 ;; (setq spec (cdr spec)))
1763 ;; )
1765 ;;;_ - Within Topic
1766 ;;;_ > allout-goto-prefix ()
1767 (defun allout-goto-prefix ()
1768 "Put point at beginning of immediately containing outline topic.
1770 Goes to most immediate subsequent topic if none immediately containing.
1772 Not sensitive to topic visibility.
1774 Returns the point at the beginning of the prefix, or nil if none."
1776 (let (done)
1777 (while (and (not done)
1778 (re-search-backward "[\n\r]" nil 1))
1779 (forward-char 1)
1780 (if (looking-at allout-regexp)
1781 (setq done (allout-prefix-data (match-beginning 0)
1782 (match-end 0)))
1783 (forward-char -1)))
1784 (if (bobp)
1785 (cond ((looking-at allout-regexp)
1786 (allout-prefix-data (match-beginning 0)(match-end 0)))
1787 ((allout-next-heading))
1788 (done))
1789 done)))
1790 ;;;_ > allout-end-of-prefix ()
1791 (defun allout-end-of-prefix (&optional ignore-decorations)
1792 "Position cursor at beginning of header text.
1794 If optional IGNORE-DECORATIONS is non-nil, put just after bullet,
1795 otherwise skip white space between bullet and ensuing text."
1797 (if (not (allout-goto-prefix))
1799 (let ((match-data (match-data)))
1800 (goto-char (match-end 0))
1801 (if ignore-decorations
1803 (while (looking-at "[0-9]") (forward-char 1))
1804 (if (and (not (eolp)) (looking-at "\\s-")) (forward-char 1)))
1805 (store-match-data match-data))
1806 ;; Reestablish where we are:
1807 (allout-current-depth)))
1808 ;;;_ > allout-current-bullet-pos ()
1809 (defun allout-current-bullet-pos ()
1810 "Return position of current \(visible) topic's bullet."
1812 (if (not (allout-current-depth))
1814 (1- (match-end 0))))
1815 ;;;_ > allout-back-to-current-heading ()
1816 (defun allout-back-to-current-heading ()
1817 "Move to heading line of current topic, or beginning if already on the line."
1819 (beginning-of-line)
1820 (prog1 (or (allout-on-current-heading-p)
1821 (and (re-search-backward (concat "^\\(" allout-regexp "\\)")
1823 'move)
1824 (allout-prefix-data (match-beginning 1)(match-end 1))))
1825 (if (interactive-p) (allout-end-of-prefix))))
1826 ;;;_ > allout-back-to-heading ()
1827 (defalias 'allout-back-to-heading 'allout-back-to-current-heading)
1828 ;;;_ > allout-pre-next-preface ()
1829 (defun allout-pre-next-preface ()
1830 "Skip forward to just before the next heading line.
1832 Returns that character position."
1834 (if (re-search-forward allout-line-boundary-regexp nil 'move)
1835 (prog1 (goto-char (match-beginning 0))
1836 (allout-prefix-data (match-beginning 2)(match-end 2)))))
1837 ;;;_ > allout-end-of-current-subtree ()
1838 (defun allout-end-of-current-subtree ()
1839 "Put point at the end of the last leaf in the currently visible topic."
1840 (interactive)
1841 (allout-back-to-current-heading)
1842 (let ((level (allout-recent-depth)))
1843 (allout-next-heading)
1844 (while (and (not (eobp))
1845 (> (allout-recent-depth) level))
1846 (allout-next-heading))
1847 (and (not (eobp)) (forward-char -1))
1848 (and (memq (preceding-char) '(?\n ?\r))
1849 (memq (aref (buffer-substring (max 1 (- (point) 3)) (point)) 1)
1850 '(?\n ?\r))
1851 (forward-char -1))
1852 (setq allout-recent-end-of-subtree (point))))
1853 ;;;_ > allout-beginning-of-current-entry ()
1854 (defun allout-beginning-of-current-entry ()
1855 "When not already there, position point at beginning of current topic's body.
1857 If already there, move cursor to bullet for hot-spot operation.
1858 \(See `allout-mode' doc string for details on hot-spot operation.)"
1859 (interactive)
1860 (let ((start-point (point)))
1861 (allout-end-of-prefix)
1862 (if (and (interactive-p)
1863 (= (point) start-point))
1864 (goto-char (allout-current-bullet-pos)))))
1865 ;;;_ > allout-end-of-current-entry ()
1866 (defun allout-end-of-current-entry ()
1867 "Position the point at the end of the current topics' entry."
1868 (interactive)
1869 (allout-show-entry)
1870 (prog1 (allout-pre-next-preface)
1871 (if (and (not (bobp))(looking-at "^$"))
1872 (forward-char -1))))
1873 ;;;_ > allout-end-of-current-heading ()
1874 (defun allout-end-of-current-heading ()
1875 (interactive)
1876 (allout-beginning-of-current-entry)
1877 (forward-line -1)
1878 (end-of-line))
1879 (defalias 'allout-end-of-heading 'allout-end-of-current-heading)
1881 ;;;_ - Depth-wise
1882 ;;;_ > allout-ascend-to-depth (depth)
1883 (defun allout-ascend-to-depth (depth)
1884 "Ascend to depth DEPTH, returning depth if successful, nil if not."
1885 (if (and (> depth 0)(<= depth (allout-depth)))
1886 (let ((last-good (point)))
1887 (while (and (< depth (allout-depth))
1888 (setq last-good (point))
1889 (allout-beginning-of-level)
1890 (allout-previous-heading)))
1891 (if (= (allout-recent-depth) depth)
1892 (progn (goto-char allout-recent-prefix-beginning)
1893 depth)
1894 (goto-char last-good)))))
1895 ;;;_ > allout-ascend ()
1896 (defun allout-ascend ()
1897 "Ascend one level, returning t if successful, nil if not."
1898 (if (allout-beginning-of-level)
1899 (allout-previous-heading)))
1900 ;;;_ > allout-descend-to-depth (depth)
1901 (defun allout-descend-to-depth (depth)
1902 "Descend to depth DEPTH within current topic.
1904 Returning depth if successful, nil if not."
1905 (let ((start-point (point))
1906 (start-depth (allout-depth)))
1907 (while
1908 (and (> (allout-depth) 0)
1909 (not (= depth (allout-recent-depth))) ; ... not there yet
1910 (allout-next-heading) ; ... go further
1911 (< start-depth (allout-recent-depth)))) ; ... still in topic
1912 (if (and (> (allout-depth) 0)
1913 (= (allout-recent-depth) depth))
1914 depth
1915 (goto-char start-point)
1916 nil))
1918 ;;;_ > allout-up-current-level (arg &optional dont-complain)
1919 (defun allout-up-current-level (arg &optional dont-complain interactive)
1920 "Move out ARG levels from current visible topic.
1922 Positions on heading line of containing topic. Error if unable to
1923 ascend that far, or nil if unable to ascend but optional arg
1924 DONT-COMPLAIN is non-nil."
1925 (interactive "p\np")
1926 (allout-back-to-current-heading)
1927 (let ((present-level (allout-recent-depth))
1928 (last-good (point))
1929 failed
1930 return)
1931 ;; Loop for iterating arg:
1932 (while (and (> (allout-recent-depth) 1)
1933 (> arg 0)
1934 (not (bobp))
1935 (not failed))
1936 (setq last-good (point))
1937 ;; Loop for going back over current or greater depth:
1938 (while (and (not (< (allout-recent-depth) present-level))
1939 (or (allout-previous-visible-heading 1)
1940 (not (setq failed present-level)))))
1941 (setq present-level (allout-current-depth))
1942 (setq arg (- arg 1)))
1943 (if (or failed
1944 (> arg 0))
1945 (progn (goto-char last-good)
1946 (if interactive (allout-end-of-prefix))
1947 (if (not dont-complain)
1948 (error "Can't ascend past outermost level")
1949 (if interactive (allout-end-of-prefix))
1950 nil))
1951 (if interactive (allout-end-of-prefix))
1952 allout-recent-prefix-beginning)))
1954 ;;;_ - Linear
1955 ;;;_ > allout-next-sibling (&optional depth backward)
1956 (defun allout-next-sibling (&optional depth backward)
1957 "Like `allout-forward-current-level', but respects invisible topics.
1959 Traverse at optional DEPTH, or current depth if none specified.
1961 Go backward if optional arg BACKWARD is non-nil.
1963 Return depth if successful, nil otherwise."
1965 (if (and backward (bobp))
1967 (let ((start-depth (or depth (allout-depth)))
1968 (start-point (point))
1969 last-depth)
1970 (while (and (not (if backward (bobp) (eobp)))
1971 (if backward (allout-previous-heading)
1972 (allout-next-heading))
1973 (> (setq last-depth (allout-recent-depth)) start-depth)))
1974 (if (and (not (eobp))
1975 (and (> (or last-depth (allout-depth)) 0)
1976 (= (allout-recent-depth) start-depth)))
1977 allout-recent-prefix-beginning
1978 (goto-char start-point)
1979 (if depth (allout-depth) start-depth)
1980 nil))))
1981 ;;;_ > allout-previous-sibling (&optional depth backward)
1982 (defun allout-previous-sibling (&optional depth backward)
1983 "Like `allout-forward-current-level', but backwards & respect invisible topics.
1985 Optional DEPTH specifies depth to traverse, default current depth.
1987 Optional BACKWARD reverses direction.
1989 Return depth if successful, nil otherwise."
1990 (allout-next-sibling depth (not backward))
1992 ;;;_ > allout-snug-back ()
1993 (defun allout-snug-back ()
1994 "Position cursor at end of previous topic.
1996 Presumes point is at the start of a topic prefix."
1997 (if (or (bobp) (eobp))
1999 (forward-char -1))
2000 (if (or (bobp) (not (memq (preceding-char) '(?\n ?\r))))
2002 (forward-char -1)
2003 (if (or (bobp) (not (memq (preceding-char) '(?\n ?\r))))
2004 (forward-char -1)))
2005 (point))
2006 ;;;_ > allout-beginning-of-level ()
2007 (defun allout-beginning-of-level ()
2008 "Go back to the first sibling at this level, visible or not."
2009 (allout-end-of-level 'backward))
2010 ;;;_ > allout-end-of-level (&optional backward)
2011 (defun allout-end-of-level (&optional backward)
2012 "Go to the last sibling at this level, visible or not."
2014 (let ((depth (allout-depth)))
2015 (while (allout-previous-sibling depth nil))
2016 (prog1 (allout-recent-depth)
2017 (allout-end-of-prefix))))
2018 ;;;_ > allout-next-visible-heading (arg)
2019 (defun allout-next-visible-heading (arg)
2020 "Move to the next ARG'th visible heading line, backward if arg is negative.
2022 Move as far as possible in indicated direction \(beginning or end of
2023 buffer) if headings are exhausted."
2025 (interactive "p")
2026 (let* ((backward (if (< arg 0) (setq arg (* -1 arg))))
2027 (step (if backward -1 1))
2028 (start-point (point))
2029 prev got)
2031 (while (> arg 0) ; limit condition
2032 (while (and (not (if backward (bobp)(eobp))) ; boundary condition
2033 ;; Move, skipping over all those concealed lines:
2034 (< -1 (forward-line step))
2035 (not (setq got (looking-at allout-regexp)))))
2036 ;; Register this got, it may be the last:
2037 (if got (setq prev got))
2038 (setq arg (1- arg)))
2039 (cond (got ; Last move was to a prefix:
2040 (allout-prefix-data (match-beginning 0) (match-end 0))
2041 (allout-end-of-prefix))
2042 (prev ; Last move wasn't, but prev was:
2043 (allout-prefix-data (match-beginning 0) (match-end 0)))
2044 ((not backward) (end-of-line) nil))))
2045 ;;;_ > allout-previous-visible-heading (arg)
2046 (defun allout-previous-visible-heading (arg)
2047 "Move to the previous heading line.
2049 With argument, repeats or can move forward if negative.
2050 A heading line is one that starts with a `*' (or that `allout-regexp'
2051 matches)."
2052 (interactive "p")
2053 (allout-next-visible-heading (- arg)))
2054 ;;;_ > allout-forward-current-level (arg)
2055 (defun allout-forward-current-level (arg &optional interactive)
2056 "Position point at the next heading of the same level.
2058 Takes optional repeat-count, goes backward if count is negative.
2060 Returns resulting position, else nil if none found."
2061 (interactive "p\np")
2062 (let ((start-depth (allout-current-depth))
2063 (start-point (point))
2064 (start-arg arg)
2065 (backward (> 0 arg))
2066 last-depth
2067 (last-good (point))
2068 at-boundary)
2069 (if (= 0 start-depth)
2070 (error "No siblings, not in a topic..."))
2071 (if backward (setq arg (* -1 arg)))
2072 (while (not (or (zerop arg)
2073 at-boundary))
2074 (while (and (not (if backward (bobp) (eobp)))
2075 (if backward (allout-previous-visible-heading 1)
2076 (allout-next-visible-heading 1))
2077 (> (setq last-depth (allout-recent-depth)) start-depth)))
2078 (if (and last-depth (= last-depth start-depth)
2079 (not (if backward (bobp) (eobp))))
2080 (setq last-good (point)
2081 arg (1- arg))
2082 (setq at-boundary t)))
2083 (if (and (not (eobp))
2084 (= arg 0)
2085 (and (> (or last-depth (allout-depth)) 0)
2086 (= (allout-recent-depth) start-depth)))
2087 allout-recent-prefix-beginning
2088 (goto-char last-good)
2089 (if (not interactive)
2091 (allout-end-of-prefix)
2092 (error "Hit %s level %d topic, traversed %d of %d requested"
2093 (if backward "first" "last")
2094 (allout-recent-depth)
2095 (- (abs start-arg) arg)
2096 (abs start-arg))))))
2097 ;;;_ > allout-backward-current-level (arg)
2098 (defun allout-backward-current-level (arg &optional interactive)
2099 "Inverse of `allout-forward-current-level'."
2100 (interactive "p\np")
2101 (if interactive
2102 (let ((current-prefix-arg (* -1 arg)))
2103 (call-interactively 'allout-forward-current-level))
2104 (allout-forward-current-level (* -1 arg))))
2106 ;;;_ #5 Alteration
2108 ;;;_ - Fundamental
2109 ;;;_ > allout-before-change-protect (beg end)
2110 (defun allout-before-change-protect (beg end)
2111 "Outline before-change hook, regulates changes to concealed text.
2113 Reveal concealed text that would be changed by current command, and
2114 offer user choice to commit or forego the change. Unchanged text is
2115 reconcealed. User has option to have changed text reconcealed.
2117 Undo commands are specially treated - the user is not prompted for
2118 choice, the undoes are always committed (based on presumption that the
2119 things being undone were already subject to this regulation routine),
2120 and undoes always leave the changed stuff exposed.
2122 Changes to concealed regions are ignored while file is being written.
2123 \(This is for the sake of functions that do change the file during
2124 writes, like crypt and zip modes.)
2126 Locally bound in outline buffers to `before-change-functions', which
2127 in Emacs 19 is run before any change to the buffer.
2129 Any functions which set [`this-command' to `undo', or which set]
2130 `allout-override-protect' non-nil (as does, eg, allout-flag-chars)
2131 are exempt from this restriction."
2132 (if (and (allout-mode-p)
2133 ; allout-override-protect
2134 ; set by functions that know what
2135 ; they're doing, eg outline internals:
2136 (not allout-override-protect)
2137 (not allout-during-write-cue)
2138 (save-match-data ; Preserve operation position state.
2139 ; Both beginning and end chars must
2140 ; be exposed:
2141 (save-excursion (if (memq this-command '(newline open-line))
2142 ;; Compensate for stupid Emacs {new,
2143 ;; open-}line display optimization:
2144 (setq beg (1+ beg)
2145 end (1+ end)))
2146 (goto-char beg)
2147 (or (allout-hidden-p)
2148 (and (not (= beg end))
2149 (goto-char end)
2150 (allout-hidden-p))))))
2151 (save-match-data
2152 (if (equal this-command 'undo)
2153 ;; Allow undo without inhibition.
2154 ;; - Undoing new and open-line hits stupid Emacs redisplay
2155 ;; optimization (em 19 cmds.c, ~ line 200).
2156 ;; - Presumably, undoing what was properly protected when
2157 ;; done.
2158 ;; - Undo may be users' only recourse in protection faults.
2159 ;; So, expose what getting changed:
2160 (progn (message "Undo! - exposing concealed target...")
2161 (if (allout-hidden-p)
2162 (allout-show-children))
2163 (message "Undo!"))
2164 (let (response
2165 (rehide-completely (save-excursion (allout-goto-prefix)
2166 (allout-hidden-p)))
2167 rehide-place)
2169 (save-excursion
2170 (if (condition-case err
2171 ;; Condition case to catch keyboard quits during reads.
2172 (progn
2173 ; Give them a peek where
2174 (save-excursion
2175 (if (eolp) (setq rehide-place
2176 (allout-goto-prefix)))
2177 (allout-show-entry))
2178 ; Present the message, but...
2179 ; leave the cursor at the location
2180 ; until they respond:
2181 ; Then interpret the response:
2182 (while
2183 (progn
2184 (message (concat "Change inside concealed"
2185 " region - do it? "
2186 "(n or 'y'/'r'eclose)"))
2187 (setq response (read-char))
2188 (not
2189 (cond ((memq response '(?r ?R))
2190 (setq response 'reclose))
2191 ((memq response '(?y ?Y ? ))
2192 (setq response t))
2193 ((memq response '(?n ?N 127))
2194 (setq response nil)
2196 ((eq response ??)
2197 (message
2198 "`r' means `yes, then reclose'")
2199 nil)
2200 (t (message "Please answer y, n, or r")
2201 (sit-for 1)
2202 nil)))))
2203 response)
2204 ('quit nil))
2205 ; Continue:
2206 (if (eq response 'reclose)
2207 (save-excursion
2208 (if rehide-place (goto-char rehide-place))
2209 (if rehide-completely
2210 (allout-hide-current-entry-completely)
2211 (allout-hide-current-entry)))
2212 (if (allout-ascend-to-depth (1- (allout-recent-depth)))
2213 (allout-show-children)
2214 (allout-show-to-offshoot)))
2215 ; Prevent:
2216 (if rehide-completely
2217 (save-excursion
2218 (if rehide-place (goto-char rehide-place))
2219 (allout-hide-current-entry-completely))
2220 (allout-hide-current-entry))
2221 (error "Change within concealed region prevented"))))))
2222 ) ; if
2223 ) ; defun
2224 ;;;_ = allout-post-goto-bullet
2225 (defvar allout-post-goto-bullet nil
2226 "Outline internal var, for `allout-pre-command-business' hot-spot operation.
2228 When set, tells post-processing to reposition on topic bullet, and
2229 then unset it. Set by `allout-pre-command-business' when implementing
2230 hot-spot operation, where literal characters typed over a topic bullet
2231 are mapped to the command of the corresponding control-key on the
2232 `allout-mode-map'.")
2233 (make-variable-buffer-local 'allout-post-goto-bullet)
2234 ;;;_ > allout-post-command-business ()
2235 (defun allout-post-command-business ()
2236 "Outline `post-command-hook' function.
2238 - Null `allout-override-protect', so it's not left open.
2240 - Implement (and clear) `allout-post-goto-bullet', for hot-spot
2241 outline commands.
2243 - Massages `buffer-undo-list' so successive, standard character self-inserts
2244 are aggregated. This kludge compensates for lack of undo bunching when
2245 `before-change-functions' is used."
2247 ; Apply any external change func:
2248 (if (not (allout-mode-p)) ; In allout-mode.
2250 (setq allout-override-protect nil)
2251 (if allout-isearch-dynamic-expose
2252 (allout-isearch-rectification))
2253 (if allout-during-write-cue
2254 ;; Was used by allout-before-change-protect, done with it now:
2255 (setq allout-during-write-cue nil))
2256 ;; Undo bunching business:
2257 (if (and (listp buffer-undo-list) ; Undo history being kept.
2258 (equal this-command 'self-insert-command)
2259 (equal last-command 'self-insert-command))
2260 (let* ((prev-stuff (cdr buffer-undo-list))
2261 (before-prev-stuff (cdr (cdr prev-stuff)))
2262 cur-cell cur-from cur-to
2263 prev-cell prev-from prev-to)
2264 (if (and before-prev-stuff ; Goes back far enough to bother,
2265 (not (car prev-stuff)) ; and break before current,
2266 (not (car before-prev-stuff)) ; !and break before prev!
2267 (setq prev-cell (car (cdr prev-stuff))) ; contents now,
2268 (setq cur-cell (car buffer-undo-list)) ; contents prev.
2270 ;; cur contents denote a single char insertion:
2271 (numberp (setq cur-from (car cur-cell)))
2272 (numberp (setq cur-to (cdr cur-cell)))
2273 (= 1 (- cur-to cur-from))
2275 ;; prev contents denote fewer than aggregate-limit
2276 ;; insertions:
2277 (numberp (setq prev-from (car prev-cell)))
2278 (numberp (setq prev-to (cdr prev-cell)))
2279 ; Below threshold:
2280 (> allout-undo-aggregation (- prev-to prev-from)))
2281 (setq buffer-undo-list
2282 (cons (cons prev-from cur-to)
2283 (cdr (cdr (cdr buffer-undo-list))))))))
2284 ;; Implement -post-goto-bullet, if set: (must be after undo business)
2285 (if (and allout-post-goto-bullet
2286 (allout-current-bullet-pos))
2287 (progn (goto-char (allout-current-bullet-pos))
2288 (setq allout-post-goto-bullet nil)))
2290 ;;;_ > allout-pre-command-business ()
2291 (defun allout-pre-command-business ()
2292 "Outline `pre-command-hook' function for outline buffers.
2293 Implements special behavior when cursor is on bullet character.
2295 When the cursor is on the bullet character, self-insert characters are
2296 reinterpreted as the corresponding control-character in the
2297 `allout-mode-map'. The `allout-mode' `post-command-hook' insures that
2298 the cursor which has moved as a result of such reinterpretation is
2299 positioned on the bullet character of the destination topic.
2301 The upshot is that you can get easy, single (ie, unmodified) key
2302 outline maneuvering operations by positioning the cursor on the bullet
2303 char. When in this mode you can use regular cursor-positioning
2304 command/keystrokes to relocate the cursor off of a bullet character to
2305 return to regular interpretation of self-insert characters."
2306 (if (not (allout-mode-p))
2307 ;; Shouldn't be invoked if not in allout allout-mode, but just in case:
2309 ;; Register isearch status:
2310 (if (and (boundp 'isearch-mode) isearch-mode)
2311 (setq allout-pre-was-isearching t)
2312 (setq allout-pre-was-isearching nil))
2313 ;; Hot-spot navigation provisions:
2314 (if (and (eq this-command 'self-insert-command)
2315 (eq (point)(allout-current-bullet-pos)))
2316 (let* ((this-key-num (cond
2317 ((numberp last-command-char)
2318 last-command-char)
2319 ((fboundp 'char-to-int)
2320 (char-to-int last-command-char))
2321 (t 0)))
2322 mapped-binding)
2323 (if (zerop this-key-num)
2325 ; Map upper-register literals
2326 ; to lower register:
2327 (if (<= 96 this-key-num)
2328 (setq this-key-num (- this-key-num 32)))
2329 ; Check if we have a literal:
2330 (if (and (<= 64 this-key-num)
2331 (>= 96 this-key-num))
2332 (setq mapped-binding
2333 (lookup-key 'allout-mode-map
2334 (concat allout-command-prefix
2335 (char-to-string (- this-key-num
2336 64))))))
2337 (if mapped-binding
2338 (setq allout-post-goto-bullet t
2339 this-command mapped-binding)))))))
2340 ;;;_ > allout-find-file-hook ()
2341 (defun allout-find-file-hook ()
2342 "Activate `allout-mode' when `allout-auto-activation' & `allout-layout' are non-nil.
2344 See `allout-init' for setup instructions."
2345 (if (and allout-auto-activation
2346 (not (allout-mode-p))
2347 allout-layout)
2348 (allout-mode t)))
2349 ;;;_ > allout-isearch-rectification
2350 (defun allout-isearch-rectification ()
2351 "Rectify outline exposure before, during, or after isearch.
2353 Called as part of `allout-post-command-business'."
2355 (let ((isearching isearch-mode))
2356 (cond ((and isearching (not allout-pre-was-isearching))
2357 (allout-isearch-expose 'start))
2358 ((and isearching allout-pre-was-isearching)
2359 (allout-isearch-expose 'continue))
2360 ((and (not isearching) allout-pre-was-isearching)
2361 (allout-isearch-expose 'final))
2362 ;; Not and wasn't isearching:
2363 (t (setq allout-isearch-prior-pos nil)))))
2364 ;;;_ = allout-isearch-was-font-lock
2365 (defvar allout-isearch-was-font-lock
2366 (and (boundp 'font-lock-mode) font-lock-mode))
2368 ;;;_ > allout-flag-region (from to flag)
2369 (defmacro allout-flag-region (from to flag)
2370 "Hide or show lines from FROM to TO, via Emacs `selective-display' FLAG char.
2371 Ie, text following flag C-m \(carriage-return) is hidden until the
2372 next C-j (newline) char.
2374 Returns the endpoint of the region."
2375 `(let ((buffer-read-only nil)
2376 (allout-override-protect t))
2377 (subst-char-in-region ,from ,to
2378 (if (= ,flag ?\n) ?\r ?\n)
2379 ,flag t)))
2381 ;;;_ > allout-isearch-expose (mode)
2382 (defun allout-isearch-expose (mode)
2383 "MODE is either 'clear, 'start, 'continue, or 'final."
2384 ;; allout-isearch-prior-pos encodes exposure status of prior pos:
2385 ;; (pos was-vis header-pos end-pos)
2386 ;; pos - point of concern
2387 ;; was-vis - t, else 'topic if entire topic was exposed, 'entry otherwise
2388 ;; Do reclosure or prior pos, as necessary:
2389 (if (eq mode 'start)
2390 (setq allout-isearch-was-font-lock (and (boundp 'font-lock-mode)
2391 font-lock-mode)
2392 font-lock-mode nil)
2393 (if (eq mode 'final)
2394 (setq font-lock-mode allout-isearch-was-font-lock))
2395 (if (and allout-isearch-prior-pos
2396 (listp allout-isearch-prior-pos))
2397 ;; Conceal prior peek:
2398 (allout-flag-region (car (cdr allout-isearch-prior-pos))
2399 (car (cdr (cdr allout-isearch-prior-pos)))
2400 ?\r)))
2401 (if (allout-visible-p)
2402 (setq allout-isearch-prior-pos nil)
2403 (if (not (eq mode 'final))
2404 (setq allout-isearch-prior-pos (cons (point) (allout-show-entry)))
2405 (if isearch-mode-end-hook-quit
2407 (setq allout-isearch-prior-pos nil)
2408 (allout-show-children)))))
2409 ;;;_ > allout-enwrap-isearch ()
2410 (defun allout-enwrap-isearch ()
2411 "Impose `isearch-abort' wrapper for dynamic exposure in isearch.
2413 The function checks to ensure that the rebinding is done only once."
2414 (add-hook 'isearch-mode-end-hook 'allout-isearch-rectification))
2416 ;;; Prevent unnecessary font-lock while isearching!
2417 (defvar isearch-was-font-locking nil)
2418 (defun isearch-inhibit-font-lock ()
2419 "Inhibit `font-lock-mode' while isearching - for use on `isearch-mode-hook'."
2420 (if (and (allout-mode-p) (boundp 'font-lock-mode) font-lock-mode)
2421 (setq isearch-was-font-locking t
2422 font-lock-mode nil)))
2423 (add-hook 'isearch-mode-hook 'isearch-inhibit-font-lock)
2424 (defun isearch-reenable-font-lock ()
2425 "Reenable font-lock after isearching - for use on `isearch-mode-end-hook'."
2426 (if (and (boundp 'font-lock-mode) font-lock-mode)
2427 (if (and (allout-mode-p) isearch-was-font-locking)
2428 (setq isearch-was-font-locking nil
2429 font-lock-mode t))))
2430 (add-hook 'isearch-mode-end-hook 'isearch-reenable-font-lock)
2432 ;;;_ - Topic Format Assessment
2433 ;;;_ > allout-solicit-alternate-bullet (depth &optional current-bullet)
2434 (defun allout-solicit-alternate-bullet (depth &optional current-bullet)
2436 "Prompt for and return a bullet char as an alternative to the current one.
2438 Offer one suitable for current depth DEPTH as default."
2440 (let* ((default-bullet (or (and (stringp current-bullet) current-bullet)
2441 (allout-bullet-for-depth depth)))
2442 (sans-escapes (regexp-sans-escapes allout-bullets-string))
2443 choice)
2444 (save-excursion
2445 (goto-char (allout-current-bullet-pos))
2446 (setq choice (solicit-char-in-string
2447 (format "Select bullet: %s ('%s' default): "
2448 sans-escapes
2449 default-bullet)
2450 sans-escapes
2451 t)))
2452 (message "")
2453 (if (string= choice "") default-bullet choice))
2455 ;;;_ > allout-distinctive-bullet (bullet)
2456 (defun allout-distinctive-bullet (bullet)
2457 "True if BULLET is one of those on `allout-distinctive-bullets-string'."
2458 (string-match (regexp-quote bullet) allout-distinctive-bullets-string))
2459 ;;;_ > allout-numbered-type-prefix (&optional prefix)
2460 (defun allout-numbered-type-prefix (&optional prefix)
2461 "True if current header prefix bullet is numbered bullet."
2462 (and allout-numbered-bullet
2463 (string= allout-numbered-bullet
2464 (if prefix
2465 (allout-get-prefix-bullet prefix)
2466 (allout-get-bullet)))))
2467 ;;;_ > allout-bullet-for-depth (&optional depth)
2468 (defun allout-bullet-for-depth (&optional depth)
2469 "Return outline topic bullet suited to optional DEPTH, or current depth."
2470 ;; Find bullet in plain-bullets-string modulo DEPTH.
2471 (if allout-stylish-prefixes
2472 (char-to-string (aref allout-plain-bullets-string
2473 (% (max 0 (- depth 2))
2474 allout-plain-bullets-string-len)))
2475 allout-primary-bullet)
2478 ;;;_ - Topic Production
2479 ;;;_ > allout-make-topic-prefix (&optional prior-bullet
2480 (defun allout-make-topic-prefix (&optional prior-bullet
2482 depth
2483 solicit
2484 number-control
2485 index)
2486 ;; Depth null means use current depth, non-null means we're either
2487 ;; opening a new topic after current topic, lower or higher, or we're
2488 ;; changing level of current topic.
2489 ;; Solicit dominates specified bullet-char.
2490 ;;;_ . Doc string:
2491 "Generate a topic prefix suitable for optional arg DEPTH, or current depth.
2493 All the arguments are optional.
2495 PRIOR-BULLET indicates the bullet of the prefix being changed, or
2496 nil if none. This bullet may be preserved (other options
2497 notwithstanding) if it is on the `allout-distinctive-bullets-string',
2498 for instance.
2500 Second arg NEW indicates that a new topic is being opened after the
2501 topic at point, if non-nil. Default bullet for new topics, eg, may
2502 be set (contingent to other args) to numbered bullets if previous
2503 sibling is one. The implication otherwise is that the current topic
2504 is being adjusted - shifted or rebulleted - and we don't consider
2505 bullet or previous sibling.
2507 Third arg DEPTH forces the topic prefix to that depth, regardless of
2508 the current topics' depth.
2510 If SOLICIT is non-nil, then the choice of bullet is solicited from
2511 user. If it's a character, then that character is offered as the
2512 default, otherwise the one suited to the context \(according to
2513 distinction or depth) is offered. \(This overrides other options,
2514 including, eg, a distinctive PRIOR-BULLET.) If non-nil, then the
2515 context-specific bullet is used.
2517 Fifth arg, NUMBER-CONTROL, matters only if `allout-numbered-bullet'
2518 is non-nil *and* soliciting was not explicitly invoked. Then
2519 NUMBER-CONTROL non-nil forces prefix to either numbered or
2520 denumbered format, depending on the value of the sixth arg, INDEX.
2522 \(Note that NUMBER-CONTROL does *not* apply to level 1 topics. Sorry...)
2524 If NUMBER-CONTROL is non-nil and sixth arg INDEX is non-nil then
2525 the prefix of the topic is forced to be numbered. Non-nil
2526 NUMBER-CONTROL and nil INDEX forces non-numbered format on the
2527 bullet. Non-nil NUMBER-CONTROL and non-nil, non-number INDEX means
2528 that the index for the numbered prefix will be derived, by counting
2529 siblings back to start of level. If INDEX is a number, then that
2530 number is used as the index for the numbered prefix (allowing, eg,
2531 sequential renumbering to not require this function counting back the
2532 index for each successive sibling)."
2533 ;;;_ . Code:
2534 ;; The options are ordered in likely frequence of use, most common
2535 ;; highest, least lowest. Ie, more likely to be doing prefix
2536 ;; adjustments than soliciting, and yet more than numbering.
2537 ;; Current prefix is least dominant, but most likely to be commonly
2538 ;; specified...
2540 (let* (body
2541 numbering
2542 denumbering
2543 (depth (or depth (allout-depth)))
2544 (header-lead allout-header-prefix)
2545 (bullet-char
2547 ;; Getting value for bullet char is practically the whole job:
2549 (cond
2550 ; Simplest situation - level 1:
2551 ((<= depth 1) (setq header-lead "") allout-primary-bullet)
2552 ; Simple, too: all asterisks:
2553 (allout-old-style-prefixes
2554 ;; Cheat - make body the whole thing, null out header-lead and
2555 ;; bullet-char:
2556 (setq body (make-string depth
2557 (string-to-char allout-primary-bullet)))
2558 (setq header-lead "")
2561 ;; (Neither level 1 nor old-style, so we're space padding.
2562 ;; Sneak it in the condition of the next case, whatever it is.)
2564 ;; Solicitation overrides numbering and other cases:
2565 ((progn (setq body (make-string (- depth 2) ?\ ))
2566 ;; The actual condition:
2567 solicit)
2568 (let* ((got (allout-solicit-alternate-bullet depth solicit)))
2569 ;; Gotta check whether we're numbering and got a numbered bullet:
2570 (setq numbering (and allout-numbered-bullet
2571 (not (and number-control (not index)))
2572 (string= got allout-numbered-bullet)))
2573 ;; Now return what we got, regardless:
2574 got))
2576 ;; Numbering invoked through args:
2577 ((and allout-numbered-bullet number-control)
2578 (if (setq numbering (not (setq denumbering (not index))))
2579 allout-numbered-bullet
2580 (if (and prior-bullet
2581 (not (string= allout-numbered-bullet
2582 prior-bullet)))
2583 prior-bullet
2584 (allout-bullet-for-depth depth))))
2586 ;;; Neither soliciting nor controlled numbering ;;;
2587 ;;; (may be controlled denumbering, tho) ;;;
2589 ;; Check wrt previous sibling:
2590 ((and new ; only check for new prefixes
2591 (<= depth (allout-depth))
2592 allout-numbered-bullet ; ... & numbering enabled
2593 (not denumbering)
2594 (let ((sibling-bullet
2595 (save-excursion
2596 ;; Locate correct sibling:
2597 (or (>= depth (allout-depth))
2598 (allout-ascend-to-depth depth))
2599 (allout-get-bullet))))
2600 (if (and sibling-bullet
2601 (string= allout-numbered-bullet sibling-bullet))
2602 (setq numbering sibling-bullet)))))
2604 ;; Distinctive prior bullet?
2605 ((and prior-bullet
2606 (allout-distinctive-bullet prior-bullet)
2607 ;; Either non-numbered:
2608 (or (not (and allout-numbered-bullet
2609 (string= prior-bullet allout-numbered-bullet)))
2610 ;; or numbered, and not denumbering:
2611 (setq numbering (not denumbering)))
2612 ;; Here 'tis:
2613 prior-bullet))
2615 ;; Else, standard bullet per depth:
2616 ((allout-bullet-for-depth depth)))))
2618 (concat header-lead
2619 body
2620 bullet-char
2621 (if numbering
2622 (format "%d" (cond ((and index (numberp index)) index)
2623 (new (1+ (allout-sibling-index depth)))
2624 ((allout-sibling-index))))))
2627 ;;;_ > allout-open-topic (relative-depth &optional before use-sib-bullet)
2628 (defun allout-open-topic (relative-depth &optional before use-sib-bullet)
2629 "Open a new topic at depth RELATIVE-DEPTH.
2631 New topic is situated after current one, unless optional flag BEFORE
2632 is non-nil, or unless current line is complete empty (not even
2633 whitespace), in which case open is done on current line.
2635 If USE-SIB-BULLET is true, use the bullet of the prior sibling.
2637 Nuances:
2639 - Creation of new topics is with respect to the visible topic
2640 containing the cursor, regardless of intervening concealed ones.
2642 - New headers are generally created after/before the body of a
2643 topic. However, they are created right at cursor location if the
2644 cursor is on a blank line, even if that breaks the current topic
2645 body. This is intentional, to provide a simple means for
2646 deliberately dividing topic bodies.
2648 - Double spacing of topic lists is preserved. Also, the first
2649 level two topic is created double-spaced (and so would be
2650 subsequent siblings, if that's left intact). Otherwise,
2651 single-spacing is used.
2653 - Creation of sibling or nested topics is with respect to the topic
2654 you're starting from, even when creating backwards. This way you
2655 can easily create a sibling in front of the current topic without
2656 having to go to its preceding sibling, and then open forward
2657 from there."
2659 (let* ((depth (+ (allout-current-depth) relative-depth))
2660 (opening-on-blank (if (looking-at "^\$")
2661 (not (setq before nil))))
2662 opening-numbered ; Will get while computing ref-topic, below
2663 ref-depth ; Will get while computing ref-topic, below
2664 ref-bullet ; Will get while computing ref-topic, next
2665 (ref-topic (save-excursion
2666 (cond ((< relative-depth 0)
2667 (allout-ascend-to-depth depth))
2668 ((>= relative-depth 1) nil)
2669 (t (allout-back-to-current-heading)))
2670 (setq ref-depth (allout-recent-depth))
2671 (setq ref-bullet
2672 (if (> allout-recent-prefix-end 1)
2673 (allout-recent-bullet)
2674 ""))
2675 (setq opening-numbered
2676 (save-excursion
2677 (and allout-numbered-bullet
2678 (or (<= relative-depth 0)
2679 (allout-descend-to-depth depth))
2680 (if (allout-numbered-type-prefix)
2681 allout-numbered-bullet))))
2682 (point)))
2683 dbl-space
2684 doing-beginning)
2686 (if (not opening-on-blank)
2687 ; Positioning and vertical
2688 ; padding - only if not
2689 ; opening-on-blank:
2690 (progn
2691 (goto-char ref-topic)
2692 (setq dbl-space ; Determine double space action:
2693 (or (and (<= relative-depth 0) ; not descending;
2694 (save-excursion
2695 ;; at b-o-b or preceded by a blank line?
2696 (or (> 0 (forward-line -1))
2697 (looking-at "^\\s-*$")
2698 (bobp)))
2699 (save-excursion
2700 ;; succeeded by a blank line?
2701 (allout-end-of-current-subtree)
2702 (bolp)))
2703 (and (= ref-depth 1)
2704 (or before
2705 (= depth 1)
2706 (save-excursion
2707 ;; Don't already have following
2708 ;; vertical padding:
2709 (not (allout-pre-next-preface)))))))
2711 ; Position to prior heading,
2712 ; if inserting backwards, and
2713 ; not going outwards:
2714 (if (and before (>= relative-depth 0))
2715 (progn (allout-back-to-current-heading)
2716 (setq doing-beginning (bobp))
2717 (if (not (bobp))
2718 (allout-previous-heading)))
2719 (if (and before (bobp))
2720 (allout-unprotected (open-line 1))))
2722 (if (<= relative-depth 0)
2723 ;; Not going inwards, don't snug up:
2724 (if doing-beginning
2725 (allout-unprotected (open-line (if dbl-space 2 1)))
2726 (if before
2727 (progn (end-of-line)
2728 (allout-pre-next-preface)
2729 (while (= ?\r (following-char))
2730 (forward-char 1))
2731 (if (not (looking-at "^$"))
2732 (allout-unprotected (open-line 1))))
2733 (allout-end-of-current-subtree)))
2734 ;; Going inwards - double-space if first offspring is,
2735 ;; otherwise snug up.
2736 (end-of-line) ; So we skip any concealed progeny.
2737 (allout-pre-next-preface)
2738 (if (bolp)
2739 ;; Blank lines between current header body and next
2740 ;; header - get to last substantive (non-white-space)
2741 ;; line in body:
2742 (re-search-backward "[^ \t\n]" nil t))
2743 (if (save-excursion
2744 (allout-next-heading)
2745 (if (> (allout-recent-depth) ref-depth)
2746 ;; This is an offspring.
2747 (progn (forward-line -1)
2748 (looking-at "^\\s-*$"))))
2749 (progn (forward-line 1)
2750 (allout-unprotected (open-line 1))))
2751 (end-of-line))
2752 ;;(if doing-beginning (goto-char doing-beginning))
2753 (if (not (bobp))
2754 (progn (if (and (not (> depth ref-depth))
2755 (not before))
2756 (allout-unprotected (open-line 1))
2757 (if (> depth ref-depth)
2758 (allout-unprotected (newline 1))
2759 (if dbl-space
2760 (allout-unprotected (open-line 1))
2761 (if (not before)
2762 (allout-unprotected (newline 1))))))
2763 (if dbl-space
2764 (allout-unprotected (newline 1)))
2765 (if (and (not (eobp))
2766 (not (bolp)))
2767 (forward-char 1))))
2769 (insert (concat (allout-make-topic-prefix opening-numbered
2771 depth)
2772 " "))
2774 ;;(if doing-beginning (save-excursion (newline (if dbl-space 2 1))))
2777 (allout-rebullet-heading (and use-sib-bullet ref-bullet);;; solicit
2778 depth ;;; depth
2779 nil ;;; number-control
2780 nil ;;; index
2781 t) (end-of-line)
2784 ;;;_ . open-topic contingencies
2785 ;;;_ ; base topic - one from which open was issued
2786 ;;;_ , beginning char
2787 ;;;_ , amount of space before will be used, unless opening in place
2788 ;;;_ , end char will be used, unless opening before (and it still may)
2789 ;;;_ ; absolute depth of new topic
2790 ;;;_ ! insert in place - overrides most stuff
2791 ;;;_ ; relative depth of new re base
2792 ;;;_ ; before or after base topic
2793 ;;;_ ; spacing around topic, if any, prior to new topic and at same depth
2794 ;;;_ ; buffer boundaries - special provisions for beginning and end ob
2795 ;;;_ ; level 1 topics have special provisions also - double space.
2796 ;;;_ ; location of new topic
2797 ;;;_ > allout-open-subtopic (arg)
2798 (defun allout-open-subtopic (arg)
2799 "Open new topic header at deeper level than the current one.
2801 Negative universal arg means to open deeper, but place the new topic
2802 prior to the current one."
2803 (interactive "p")
2804 (allout-open-topic 1 (> 0 arg)))
2805 ;;;_ > allout-open-sibtopic (arg)
2806 (defun allout-open-sibtopic (arg)
2807 "Open new topic header at same level as the current one.
2809 Positive universal arg means to use the bullet of the prior sibling.
2811 Negative universal arg means to place the new topic prior to the current
2812 one."
2813 (interactive "p")
2814 (allout-open-topic 0 (> 0 arg) (< 1 arg)))
2815 ;;;_ > allout-open-supertopic (arg)
2816 (defun allout-open-supertopic (arg)
2817 "Open new topic header at shallower level than the current one.
2819 Negative universal arg means to open shallower, but place the new
2820 topic prior to the current one."
2822 (interactive "p")
2823 (allout-open-topic -1 (> 0 arg)))
2825 ;;;_ - Outline Alteration
2826 ;;;_ : Topic Modification
2827 ;;;_ = allout-former-auto-filler
2828 (defvar allout-former-auto-filler nil
2829 "Name of modal fill function being wrapped by `allout-auto-fill'.")
2830 ;;;_ > allout-auto-fill ()
2831 (defun allout-auto-fill ()
2832 "`allout-mode' autofill function.
2834 Maintains outline hanging topic indentation if
2835 `allout-use-hanging-indents' is set."
2836 (let ((fill-prefix (if allout-use-hanging-indents
2837 ;; Check for topic header indentation:
2838 (save-excursion
2839 (beginning-of-line)
2840 (if (looking-at allout-regexp)
2841 ;; ... construct indentation to account for
2842 ;; length of topic prefix:
2843 (make-string (progn (allout-end-of-prefix)
2844 (current-column))
2845 ?\ ))))))
2846 (if (or allout-former-auto-filler allout-use-hanging-indents)
2847 (do-auto-fill))))
2848 ;;;_ > allout-reindent-body (old-depth new-depth &optional number)
2849 (defun allout-reindent-body (old-depth new-depth &optional number)
2850 "Reindent body lines which were indented at OLD-DEPTH to NEW-DEPTH.
2852 Optional arg NUMBER indicates numbering is being added, and it must
2853 be accommodated.
2855 Note that refill of indented paragraphs is not done."
2857 (save-excursion
2858 (allout-end-of-prefix)
2859 (let* ((new-margin (current-column))
2860 excess old-indent-begin old-indent-end
2861 curr-ind
2862 ;; We want the column where the header-prefix text started
2863 ;; *before* the prefix was changed, so we infer it relative
2864 ;; to the new margin and the shift in depth:
2865 (old-margin (+ old-depth (- new-margin new-depth))))
2867 ;; Process lines up to (but excluding) next topic header:
2868 (allout-unprotected
2869 (save-match-data
2870 (while
2871 (and (re-search-forward "[\n\r]\\(\\s-*\\)"
2874 ;; Register the indent data, before we reset the
2875 ;; match data with a subsequent `looking-at':
2876 (setq old-indent-begin (match-beginning 1)
2877 old-indent-end (match-end 1))
2878 (not (looking-at allout-regexp)))
2879 (if (> 0 (setq excess (- (current-column)
2880 old-margin)))
2881 ;; Text starts left of old margin - don't adjust:
2883 ;; Text was hanging at or right of old left margin -
2884 ;; reindent it, preserving its existing indentation
2885 ;; beyond the old margin:
2886 (delete-region old-indent-begin old-indent-end)
2887 (indent-to (+ new-margin excess)))))))))
2888 ;;;_ > allout-rebullet-current-heading (arg)
2889 (defun allout-rebullet-current-heading (arg)
2890 "Solicit new bullet for current visible heading."
2891 (interactive "p")
2892 (let ((initial-col (current-column))
2893 (on-bullet (eq (point)(allout-current-bullet-pos)))
2894 (backwards (if (< arg 0)
2895 (setq arg (* arg -1)))))
2896 (while (> arg 0)
2897 (save-excursion (allout-back-to-current-heading)
2898 (allout-end-of-prefix)
2899 (allout-rebullet-heading t ;;; solicit
2900 nil ;;; depth
2901 nil ;;; number-control
2902 nil ;;; index
2903 t)) ;;; do-successors
2904 (setq arg (1- arg))
2905 (if (<= arg 0)
2907 (setq initial-col nil) ; Override positioning back to init col
2908 (if (not backwards)
2909 (allout-next-visible-heading 1)
2910 (allout-goto-prefix)
2911 (allout-next-visible-heading -1))))
2912 (message "Done.")
2913 (cond (on-bullet (goto-char (allout-current-bullet-pos)))
2914 (initial-col (move-to-column initial-col)))))
2915 ;;;_ > allout-rebullet-heading (&optional solicit ...)
2916 (defun allout-rebullet-heading (&optional solicit
2917 new-depth
2918 number-control
2919 index
2920 do-successors)
2922 "Adjust bullet of current topic prefix.
2924 If SOLICIT is non-nil, then the choice of bullet is solicited from
2925 user. If it's a character, then that character is offered as the
2926 default, otherwise the one suited to the context \(according to
2927 distinction or depth) is offered. If non-nil, then the
2928 context-specific bullet is just used.
2930 Second arg NEW-DEPTH forces the topic prefix to that depth, regardless
2931 of the topic's current depth.
2933 Third arg NUMBER-CONTROL can force the prefix to or away from
2934 numbered form. It has effect only if `allout-numbered-bullet' is
2935 non-nil and soliciting was not explicitly invoked (via first arg).
2936 Its effect, numbering or denumbering, then depends on the setting
2937 of the fourth arg, INDEX.
2939 If NUMBER-CONTROL is non-nil and fourth arg INDEX is nil, then the
2940 prefix of the topic is forced to be non-numbered. Null index and
2941 non-nil NUMBER-CONTROL forces denumbering. Non-nil INDEX (and
2942 non-nil NUMBER-CONTROL) forces a numbered-prefix form. If non-nil
2943 INDEX is a number, then that number is used for the numbered
2944 prefix. Non-nil and non-number means that the index for the
2945 numbered prefix will be derived by `allout-make-topic-prefix'.
2947 Fifth arg DO-SUCCESSORS t means re-resolve count on succeeding
2948 siblings.
2950 Cf vars `allout-stylish-prefixes', `allout-old-style-prefixes',
2951 and `allout-numbered-bullet', which all affect the behavior of
2952 this function."
2954 (let* ((current-depth (allout-depth))
2955 (new-depth (or new-depth current-depth))
2956 (mb allout-recent-prefix-beginning)
2957 (me allout-recent-prefix-end)
2958 (current-bullet (buffer-substring (- me 1) me))
2959 (new-prefix (allout-make-topic-prefix current-bullet
2961 new-depth
2962 solicit
2963 number-control
2964 index)))
2966 ;; Is new one is identical to old?
2967 (if (and (= current-depth new-depth)
2968 (string= current-bullet
2969 (substring new-prefix (1- (length new-prefix)))))
2970 ;; Nothing to do:
2973 ;; New prefix probably different from old:
2974 ; get rid of old one:
2975 (allout-unprotected (delete-region mb me))
2976 (goto-char mb)
2977 ; Dispense with number if
2978 ; numbered-bullet prefix:
2979 (if (and allout-numbered-bullet
2980 (string= allout-numbered-bullet current-bullet)
2981 (looking-at "[0-9]+"))
2982 (allout-unprotected
2983 (delete-region (match-beginning 0)(match-end 0))))
2985 ; Put in new prefix:
2986 (allout-unprotected (insert new-prefix))
2988 ;; Reindent the body if elected and margin changed:
2989 (if (and allout-reindent-bodies
2990 (not (= new-depth current-depth)))
2991 (allout-reindent-body current-depth new-depth))
2993 ;; Recursively rectify successive siblings of orig topic if
2994 ;; caller elected for it:
2995 (if do-successors
2996 (save-excursion
2997 (while (allout-next-sibling new-depth nil)
2998 (setq index
2999 (cond ((numberp index) (1+ index))
3000 ((not number-control) (allout-sibling-index))))
3001 (if (allout-numbered-type-prefix)
3002 (allout-rebullet-heading nil ;;; solicit
3003 new-depth ;;; new-depth
3004 number-control;;; number-control
3005 index ;;; index
3006 nil))))) ;;;(dont!)do-successors
3007 ) ; (if (and (= current-depth new-depth)...))
3008 ) ; let* ((current-depth (allout-depth))...)
3009 ) ; defun
3010 ;;;_ > allout-rebullet-topic (arg)
3011 (defun allout-rebullet-topic (arg)
3012 "Like `allout-rebullet-topic-grunt', but start from topic visible at point.
3014 Descends into invisible as well as visible topics, however.
3016 With repeat count, shift topic depth by that amount."
3017 (interactive "P")
3018 (let ((start-col (current-column))
3019 (was-eol (eolp)))
3020 (save-excursion
3021 ;; Normalize arg:
3022 (cond ((null arg) (setq arg 0))
3023 ((listp arg) (setq arg (car arg))))
3024 ;; Fill the user in, in case we're shifting a big topic:
3025 (if (not (zerop arg)) (message "Shifting..."))
3026 (allout-back-to-current-heading)
3027 (if (<= (+ (allout-recent-depth) arg) 0)
3028 (error "Attempt to shift topic below level 1"))
3029 (allout-rebullet-topic-grunt arg)
3030 (if (not (zerop arg)) (message "Shifting... done.")))
3031 (move-to-column (max 0 (+ start-col arg)))))
3032 ;;;_ > allout-rebullet-topic-grunt (&optional relative-depth ...)
3033 (defun allout-rebullet-topic-grunt (&optional relative-depth
3034 starting-depth
3035 starting-point
3036 index
3037 do-successors)
3039 "Rebullet the topic at point, visible or invisible, and all
3040 contained subtopics. See `allout-rebullet-heading' for rebulleting
3041 behavior.
3043 Arg RELATIVE-DEPTH means to shift the depth of the entire
3044 topic that amount.
3046 \(fn &optional RELATIVE-DEPTH)"
3048 ;; All args except the first one are for internal recursive use by the
3049 ;; function itself.
3051 (let* ((relative-depth (or relative-depth 0))
3052 (new-depth (allout-depth))
3053 (starting-depth (or starting-depth new-depth))
3054 (on-starting-call (null starting-point))
3055 (index (or index
3056 ;; Leave index null on starting call, so rebullet-heading
3057 ;; calculates it at what might be new depth:
3058 (and (or (zerop relative-depth)
3059 (not on-starting-call))
3060 (allout-sibling-index))))
3061 (moving-outwards (< 0 relative-depth))
3062 (starting-point (or starting-point (point))))
3064 ;; Sanity check for excessive promotion done only on starting call:
3065 (and on-starting-call
3066 moving-outwards
3067 (> 0 (+ starting-depth relative-depth))
3068 (error "Attempt to shift topic out beyond level 1")) ;;; ====>
3070 (cond ((= starting-depth new-depth)
3071 ;; We're at depth to work on this one:
3072 (allout-rebullet-heading nil ;;; solicit
3073 (+ starting-depth ;;; starting-depth
3074 relative-depth)
3075 nil ;;; number
3076 index ;;; index
3077 ;; Every contained topic will get hit,
3078 ;; and we have to get to outside ones
3079 ;; deliberately:
3080 nil) ;;; do-successors
3081 ;; ... and work on subsequent ones which are at greater depth:
3082 (setq index 0)
3083 (allout-next-heading)
3084 (while (and (not (eobp))
3085 (< starting-depth (allout-recent-depth)))
3086 (setq index (1+ index))
3087 (allout-rebullet-topic-grunt relative-depth ;;; relative-depth
3088 (1+ starting-depth);;;starting-depth
3089 starting-point ;;; starting-point
3090 index))) ;;; index
3092 ((< starting-depth new-depth)
3093 ;; Rare case - subtopic more than one level deeper than parent.
3094 ;; Treat this one at an even deeper level:
3095 (allout-rebullet-topic-grunt relative-depth ;;; relative-depth
3096 new-depth ;;; starting-depth
3097 starting-point ;;; starting-point
3098 index))) ;;; index
3100 (if on-starting-call
3101 (progn
3102 ;; Rectify numbering of former siblings of the adjusted topic,
3103 ;; if topic has changed depth
3104 (if (or do-successors
3105 (and (not (zerop relative-depth))
3106 (or (= (allout-recent-depth) starting-depth)
3107 (= (allout-recent-depth) (+ starting-depth
3108 relative-depth)))))
3109 (allout-rebullet-heading nil nil nil nil t))
3110 ;; Now rectify numbering of new siblings of the adjusted topic,
3111 ;; if depth has been changed:
3112 (progn (goto-char starting-point)
3113 (if (not (zerop relative-depth))
3114 (allout-rebullet-heading nil nil nil nil t)))))
3117 ;;;_ > allout-renumber-to-depth (&optional depth)
3118 (defun allout-renumber-to-depth (&optional depth)
3119 "Renumber siblings at current depth.
3121 Affects superior topics if optional arg DEPTH is less than current depth.
3123 Returns final depth."
3125 ;; Proceed by level, processing subsequent siblings on each,
3126 ;; ascending until we get shallower than the start depth:
3128 (let ((ascender (allout-depth))
3129 was-eobp)
3130 (while (and (not (eobp))
3131 (allout-depth)
3132 (>= (allout-recent-depth) depth)
3133 (>= ascender depth))
3134 ; Skip over all topics at
3135 ; lesser depths, which can not
3136 ; have been disturbed:
3137 (while (and (not (setq was-eobp (eobp)))
3138 (> (allout-recent-depth) ascender))
3139 (allout-next-heading))
3140 ; Prime ascender for ascension:
3141 (setq ascender (1- (allout-recent-depth)))
3142 (if (>= (allout-recent-depth) depth)
3143 (allout-rebullet-heading nil ;;; solicit
3144 nil ;;; depth
3145 nil ;;; number-control
3146 nil ;;; index
3147 t)) ;;; do-successors
3148 (if was-eobp (goto-char (point-max)))))
3149 (allout-recent-depth))
3150 ;;;_ > allout-number-siblings (&optional denumber)
3151 (defun allout-number-siblings (&optional denumber)
3152 "Assign numbered topic prefix to this topic and its siblings.
3154 With universal argument, denumber - assign default bullet to this
3155 topic and its siblings.
3157 With repeated universal argument (`^U^U'), solicit bullet for each
3158 rebulleting each topic at this level."
3160 (interactive "P")
3162 (save-excursion
3163 (allout-back-to-current-heading)
3164 (allout-beginning-of-level)
3165 (let ((depth (allout-recent-depth))
3166 (index (if (not denumber) 1))
3167 (use-bullet (equal '(16) denumber))
3168 (more t))
3169 (while more
3170 (allout-rebullet-heading use-bullet ;;; solicit
3171 depth ;;; depth
3172 t ;;; number-control
3173 index ;;; index
3174 nil) ;;; do-successors
3175 (if index (setq index (1+ index)))
3176 (setq more (allout-next-sibling depth nil))))))
3177 ;;;_ > allout-shift-in (arg)
3178 (defun allout-shift-in (arg)
3179 "Increase depth of current heading and any topics collapsed within it."
3180 (interactive "p")
3181 (allout-rebullet-topic arg))
3182 ;;;_ > allout-shift-out (arg)
3183 (defun allout-shift-out (arg)
3184 "Decrease depth of current heading and any topics collapsed within it."
3185 (interactive "p")
3186 (allout-rebullet-topic (* arg -1)))
3187 ;;;_ : Surgery (kill-ring) functions with special provisions for outlines:
3188 ;;;_ > allout-kill-line (&optional arg)
3189 (defun allout-kill-line (&optional arg)
3190 "Kill line, adjusting subsequent lines suitably for outline mode."
3192 (interactive "*P")
3193 (if (not (and (allout-mode-p) ; active outline mode,
3194 allout-numbered-bullet ; numbers may need adjustment,
3195 (bolp) ; may be clipping topic head,
3196 (looking-at allout-regexp))) ; are clipping topic head.
3197 ;; Above conditions do not obtain - just do a regular kill:
3198 (kill-line arg)
3199 ;; Ah, have to watch out for adjustments:
3200 (let* ((depth (allout-depth)))
3201 ; Do the kill:
3202 (kill-line arg)
3203 ; Provide some feedback:
3204 (sit-for 0)
3205 (save-excursion
3206 ; Start with the topic
3207 ; following killed line:
3208 (if (not (looking-at allout-regexp))
3209 (allout-next-heading))
3210 (allout-renumber-to-depth depth)))))
3211 ;;;_ > allout-kill-topic ()
3212 (defun allout-kill-topic ()
3213 "Kill topic together with subtopics.
3215 Leaves primary topic's trailing vertical whitespace, if any."
3217 ;; Some finagling is done to make complex topic kills appear faster
3218 ;; than they actually are. A redisplay is performed immediately
3219 ;; after the region is disposed of, though the renumbering process
3220 ;; has yet to be performed. This means that there may appear to be
3221 ;; a lag *after* the kill has been performed.
3223 (interactive)
3224 (let* ((beg (prog1 (allout-back-to-current-heading)(beginning-of-line)))
3225 (depth (allout-recent-depth)))
3226 (allout-end-of-current-subtree)
3227 (if (not (eobp))
3228 (if (or (not (looking-at "^$"))
3229 ;; A blank line - cut it with this topic *unless* this
3230 ;; is the last topic at this level, in which case
3231 ;; we'll leave the blank line as part of the
3232 ;; containing topic:
3233 (save-excursion
3234 (and (allout-next-heading)
3235 (>= (allout-recent-depth) depth))))
3236 (forward-char 1)))
3238 (kill-region beg (point))
3239 (sit-for 0)
3240 (save-excursion
3241 (allout-renumber-to-depth depth))))
3242 ;;;_ > allout-yank-processing ()
3243 (defun allout-yank-processing (&optional arg)
3245 "Incidental outline specific business to be done just after text yanks.
3247 Does depth adjustment of yanked topics, when:
3249 1 the stuff being yanked starts with a valid outline header prefix, and
3250 2 it is being yanked at the end of a line which consists of only a valid
3251 topic prefix.
3253 Also, adjusts numbering of subsequent siblings when appropriate.
3255 Depth adjustment alters the depth of all the topics being yanked
3256 the amount it takes to make the first topic have the depth of the
3257 header into which it's being yanked.
3259 The point is left in front of yanked, adjusted topics, rather than
3260 at the end (and vice-versa with the mark). Non-adjusted yanks,
3261 however, are left exactly like normal, not outline specific yanks."
3263 (interactive "*P")
3264 ; Get to beginning, leaving
3265 ; region around subject:
3266 (if (< (my-mark-marker t) (point))
3267 (exchange-point-and-mark))
3268 (let* ((subj-beg (point))
3269 (subj-end (my-mark-marker t))
3270 ;; 'resituate' if yanking an entire topic into topic header:
3271 (resituate (and (allout-e-o-prefix-p)
3272 (looking-at (concat "\\(" allout-regexp "\\)"))
3273 (allout-prefix-data (match-beginning 1)
3274 (match-end 1))))
3275 ;; `rectify-numbering' if resituating (where several topics may
3276 ;; be resituating) or yanking a topic into a topic slot (bol):
3277 (rectify-numbering (or resituate
3278 (and (bolp) (looking-at allout-regexp)))))
3279 (if resituate
3280 ; The yanked stuff is a topic:
3281 (let* ((prefix-len (- (match-end 1) subj-beg))
3282 (subj-depth (allout-recent-depth))
3283 (prefix-bullet (allout-recent-bullet))
3284 (adjust-to-depth
3285 ;; Nil if adjustment unnecessary, otherwise depth to which
3286 ;; adjustment should be made:
3287 (save-excursion
3288 (and (goto-char subj-end)
3289 (eolp)
3290 (goto-char subj-beg)
3291 (and (looking-at allout-regexp)
3292 (progn
3293 (beginning-of-line)
3294 (not (= (point) subj-beg)))
3295 (looking-at allout-regexp)
3296 (allout-prefix-data (match-beginning 0)
3297 (match-end 0)))
3298 (allout-recent-depth))))
3299 done
3300 (more t))
3301 (setq rectify-numbering allout-numbered-bullet)
3302 (if adjust-to-depth
3303 ; Do the adjustment:
3304 (progn
3305 (message "... yanking") (sit-for 0)
3306 (save-restriction
3307 (narrow-to-region subj-beg subj-end)
3308 ; Trim off excessive blank
3309 ; line at end, if any:
3310 (goto-char (point-max))
3311 (if (looking-at "^$")
3312 (allout-unprotected (delete-char -1)))
3313 ; Work backwards, with each
3314 ; shallowest level,
3315 ; successively excluding the
3316 ; last processed topic from
3317 ; the narrow region:
3318 (while more
3319 (allout-back-to-current-heading)
3320 ; go as high as we can in each bunch:
3321 (while (allout-ascend-to-depth (1- (allout-depth))))
3322 (save-excursion
3323 (allout-rebullet-topic-grunt (- adjust-to-depth
3324 subj-depth))
3325 (allout-depth))
3326 (if (setq more (not (bobp)))
3327 (progn (widen)
3328 (forward-char -1)
3329 (narrow-to-region subj-beg (point))))))
3330 (message "")
3331 ;; Preserve new bullet if it's a distinctive one, otherwise
3332 ;; use old one:
3333 (if (string-match (regexp-quote prefix-bullet)
3334 allout-distinctive-bullets-string)
3335 ; Delete from bullet of old to
3336 ; before bullet of new:
3337 (progn
3338 (beginning-of-line)
3339 (delete-region (point) subj-beg)
3340 (set-marker (my-mark-marker t) subj-end)
3341 (goto-char subj-beg)
3342 (allout-end-of-prefix))
3343 ; Delete base subj prefix,
3344 ; leaving old one:
3345 (delete-region (point) (+ (point)
3346 prefix-len
3347 (- adjust-to-depth subj-depth)))
3348 ; and delete residual subj
3349 ; prefix digits and space:
3350 (while (looking-at "[0-9]") (delete-char 1))
3351 (if (looking-at " ") (delete-char 1))))
3352 (exchange-point-and-mark))))
3353 (if rectify-numbering
3354 (progn
3355 (save-excursion
3356 ; Give some preliminary feedback:
3357 (message "... reconciling numbers") (sit-for 0)
3358 ; ... and renumber, in case necessary:
3359 (goto-char subj-beg)
3360 (if (allout-goto-prefix)
3361 (allout-rebullet-heading nil ;;; solicit
3362 (allout-depth) ;;; depth
3363 nil ;;; number-control
3364 nil ;;; index
3366 (message ""))))
3367 (if (not resituate)
3368 (exchange-point-and-mark))))
3369 ;;;_ > allout-yank (&optional arg)
3370 (defun allout-yank (&optional arg)
3371 "`allout-mode' yank, with depth and numbering adjustment of yanked topics.
3373 Non-topic yanks work no differently than normal yanks.
3375 If a topic is being yanked into a bare topic prefix, the depth of the
3376 yanked topic is adjusted to the depth of the topic prefix.
3378 1 we're yanking in an `allout-mode' buffer
3379 2 the stuff being yanked starts with a valid outline header prefix, and
3380 3 it is being yanked at the end of a line which consists of only a valid
3381 topic prefix.
3383 If these conditions hold then the depth of the yanked topics are all
3384 adjusted the amount it takes to make the first one at the depth of the
3385 header into which it's being yanked.
3387 The point is left in front of yanked, adjusted topics, rather than
3388 at the end (and vice-versa with the mark). Non-adjusted yanks,
3389 however, (ones that don't qualify for adjustment) are handled
3390 exactly like normal yanks.
3392 Numbering of yanked topics, and the successive siblings at the depth
3393 into which they're being yanked, is adjusted.
3395 `allout-yank-pop' works with `allout-yank' just like normal `yank-pop'
3396 works with normal `yank' in non-outline buffers."
3398 (interactive "*P")
3399 (setq this-command 'yank)
3400 (yank arg)
3401 (if (allout-mode-p)
3402 (allout-yank-processing)))
3403 ;;;_ > allout-yank-pop (&optional arg)
3404 (defun allout-yank-pop (&optional arg)
3405 "Yank-pop like `allout-yank' when popping to bare outline prefixes.
3407 Adapts level of popped topics to level of fresh prefix.
3409 Note - prefix changes to distinctive bullets will stick, if followed
3410 by pops to non-distinctive yanks. Bug..."
3412 (interactive "*p")
3413 (setq this-command 'yank)
3414 (yank-pop arg)
3415 (if (allout-mode-p)
3416 (allout-yank-processing)))
3418 ;;;_ - Specialty bullet functions
3419 ;;;_ : File Cross references
3420 ;;;_ > allout-resolve-xref ()
3421 (defun allout-resolve-xref ()
3422 "Pop to file associated with current heading, if it has an xref bullet.
3424 \(Works according to setting of `allout-file-xref-bullet')."
3425 (interactive)
3426 (if (not allout-file-xref-bullet)
3427 (error
3428 "Outline cross references disabled - no `allout-file-xref-bullet'")
3429 (if (not (string= (allout-current-bullet) allout-file-xref-bullet))
3430 (error "Current heading lacks cross-reference bullet `%s'"
3431 allout-file-xref-bullet)
3432 (let (file-name)
3433 (save-excursion
3434 (let* ((text-start allout-recent-prefix-end)
3435 (heading-end (progn (end-of-line) (point))))
3436 (goto-char text-start)
3437 (setq file-name
3438 (if (re-search-forward "\\s-\\(\\S-*\\)" heading-end t)
3439 (buffer-substring (match-beginning 1) (match-end 1))))))
3440 (setq file-name
3441 (if (not (= (aref file-name 0) ?:))
3442 (expand-file-name file-name)
3443 ; A registry-files ref, strip the `:'
3444 ; and try to follow it:
3445 (let ((reg-ref (reference-registered-file
3446 (substring file-name 1) nil t)))
3447 (if reg-ref (car (cdr reg-ref))))))
3448 (if (or (file-exists-p file-name)
3449 (if (file-writable-p file-name)
3450 (y-or-n-p (format "%s not there, create one? "
3451 file-name))
3452 (error "%s not found and can't be created" file-name)))
3453 (condition-case failure
3454 (find-file-other-window file-name)
3455 ('error failure))
3456 (error "%s not found" file-name))
3462 ;;;_ #6 Exposure Control
3464 ;;;_ - Fundamental
3465 ;;;_ > allout-flag-current-subtree (flag)
3466 (defun allout-flag-current-subtree (flag)
3467 "Hide or show subtree of currently-visible topic.
3469 See `allout-flag-region' for more details."
3471 (save-excursion
3472 (allout-back-to-current-heading)
3473 (allout-flag-region (point)
3474 (progn (allout-end-of-current-subtree) (1- (point)))
3475 flag)))
3477 ;;;_ - Topic-specific
3478 ;;;_ > allout-show-entry ()
3479 (defun allout-show-entry ()
3480 "Like `allout-show-current-entry', reveals entries nested in hidden topics.
3482 This is a way to give restricted peek at a concealed locality without the
3483 expense of exposing its context, but can leave the outline with aberrant
3484 exposure. `allout-hide-current-entry-completely' or `allout-show-to-offshoot'
3485 should be used after the peek to rectify the exposure."
3487 (interactive)
3488 (save-excursion
3489 (let ((at (point))
3490 beg end)
3491 (allout-goto-prefix)
3492 (setq beg (if (= (preceding-char) ?\r) (1- (point)) (point)))
3493 (re-search-forward "[\n\r]" nil t)
3494 (setq end (1- (if (< at (point))
3495 ;; We're on topic head line - show only it:
3496 (point)
3497 ;; or we're in body - include it:
3498 (max beg (or (allout-pre-next-preface) (point))))))
3499 (allout-flag-region beg end ?\n)
3500 (list beg end))))
3501 ;;;_ > allout-show-children (&optional level strict)
3502 (defun allout-show-children (&optional level strict)
3504 "If point is visible, show all direct subheadings of this heading.
3506 Otherwise, do `allout-show-to-offshoot', and then show subheadings.
3508 Optional LEVEL specifies how many levels below the current level
3509 should be shown, or all levels if t. Default is 1.
3511 Optional STRICT means don't resort to -show-to-offshoot, no matter
3512 what. This is basically so -show-to-offshoot, which is called by
3513 this function, can employ the pure offspring-revealing capabilities of
3516 Returns point at end of subtree that was opened, if any. (May get a
3517 point of non-opened subtree?)"
3519 (interactive "p")
3520 (let (max-pos)
3521 (if (and (not strict)
3522 (allout-hidden-p))
3524 (progn (allout-show-to-offshoot) ; Point's concealed, open to
3525 ; expose it.
3526 ;; Then recurse, but with "strict" set so we don't
3527 ;; infinite regress:
3528 (setq max-pos (allout-show-children level t)))
3530 (save-excursion
3531 (save-restriction
3532 (let* ((start-pt (point))
3533 (chart (allout-chart-subtree (or level 1)))
3534 (to-reveal (allout-chart-to-reveal chart (or level 1))))
3535 (goto-char start-pt)
3536 (if (and strict (= (preceding-char) ?\r))
3537 ;; Concealed root would already have been taken care of,
3538 ;; unless strict was set.
3539 (progn
3540 (allout-flag-region (point) (allout-snug-back) ?\n)
3541 (if allout-show-bodies
3542 (progn (goto-char (car to-reveal))
3543 (allout-show-current-entry)))))
3544 (while to-reveal
3545 (goto-char (car to-reveal))
3546 (allout-flag-region (point) (allout-snug-back) ?\n)
3547 (if allout-show-bodies
3548 (progn (goto-char (car to-reveal))
3549 (allout-show-current-entry)))
3550 (setq to-reveal (cdr to-reveal)))))))))
3551 ;;;_ > allout-hide-point-reconcile ()
3552 (defun allout-hide-reconcile ()
3553 "Like `allout-hide-current-entry'; hides completely if within hidden region.
3555 Specifically intended for aberrant exposure states, like entries that were
3556 exposed by `allout-show-entry' but are within otherwise concealed regions."
3557 (interactive)
3558 (save-excursion
3559 (allout-goto-prefix)
3560 (allout-flag-region (if (not (bobp)) (1- (point)) (point))
3561 (progn (allout-pre-next-preface)
3562 (if (= ?\r (following-char))
3563 (point)
3564 (1- (point))))
3565 ?\r)))
3566 ;;;_ > allout-show-to-offshoot ()
3567 (defun allout-show-to-offshoot ()
3568 "Like `allout-show-entry', but reveals all concealed ancestors, as well.
3570 As with `allout-hide-current-entry-completely', useful for rectifying
3571 aberrant exposure states produced by `allout-show-entry'."
3573 (interactive)
3574 (save-excursion
3575 (let ((orig-pt (point))
3576 (orig-pref (allout-goto-prefix))
3577 (last-at (point))
3578 bag-it)
3579 (while (or bag-it (= (preceding-char) ?\r))
3580 (beginning-of-line)
3581 (if (= last-at (setq last-at (point)))
3582 ;; Oops, we're not making any progress! Show the current
3583 ;; topic completely, and bag this try.
3584 (progn (beginning-of-line)
3585 (allout-show-current-subtree)
3586 (goto-char orig-pt)
3587 (setq bag-it t)
3588 (beep)
3589 (message "%s: %s"
3590 "allout-show-to-offshoot: "
3591 "Aberrant nesting encountered.")))
3592 (allout-show-children)
3593 (goto-char orig-pref))
3594 (goto-char orig-pt)))
3595 (if (allout-hidden-p)
3596 (allout-show-entry)))
3597 ;;;_ > allout-hide-current-entry ()
3598 (defun allout-hide-current-entry ()
3599 "Hide the body directly following this heading."
3600 (interactive)
3601 (allout-back-to-current-heading)
3602 (save-excursion
3603 (allout-flag-region (point)
3604 (progn (allout-end-of-current-entry) (point))
3605 ?\r)))
3606 ;;;_ > allout-show-current-entry (&optional arg)
3607 (defun allout-show-current-entry (&optional arg)
3609 "Show body following current heading, or hide the entry if repeat count."
3611 (interactive "P")
3612 (if arg
3613 (allout-hide-current-entry)
3614 (save-excursion
3615 (allout-flag-region (point)
3616 (progn (allout-end-of-current-entry) (point))
3617 ?\n))))
3618 ;;;_ > allout-hide-current-entry-completely ()
3619 ; ... allout-hide-current-entry-completely also for isearch dynamic exposure:
3620 (defun allout-hide-current-entry-completely ()
3621 "Like `allout-hide-current-entry', but conceal topic completely.
3623 Specifically intended for aberrant exposure states, like entries that were
3624 exposed by `allout-show-entry' but are within otherwise concealed regions."
3625 (interactive)
3626 (save-excursion
3627 (allout-goto-prefix)
3628 (allout-flag-region (if (not (bobp)) (1- (point)) (point))
3629 (progn (allout-pre-next-preface)
3630 (if (= ?\r (following-char))
3631 (point)
3632 (1- (point))))
3633 ?\r)))
3634 ;;;_ > allout-show-current-subtree (&optional arg)
3635 (defun allout-show-current-subtree (&optional arg)
3636 "Show everything within the current topic. With a repeat-count,
3637 expose this topic and its siblings."
3638 (interactive "P")
3639 (save-excursion
3640 (if (<= (allout-current-depth) 0)
3641 ;; Outside any topics - try to get to the first:
3642 (if (not (allout-next-heading))
3643 (error "No topics")
3644 ;; got to first, outermost topic - set to expose it and siblings:
3645 (message "Above outermost topic - exposing all.")
3646 (allout-flag-region (point-min)(point-max) ?\n))
3647 (if (not arg)
3648 (allout-flag-current-subtree ?\n)
3649 (allout-beginning-of-level)
3650 (allout-expose-topic '(* :))))))
3651 ;;;_ > allout-hide-current-subtree (&optional just-close)
3652 (defun allout-hide-current-subtree (&optional just-close)
3653 "Close the current topic, or containing topic if this one is already closed.
3655 If this topic is closed and it's a top level topic, close this topic
3656 and its siblings.
3658 If optional arg JUST-CLOSE is non-nil, do not treat the parent or
3659 siblings, even if the target topic is already closed."
3661 (interactive)
3662 (let ((from (point))
3663 (orig-eol (progn (end-of-line)
3664 (if (not (allout-goto-prefix))
3665 (error "No topics found")
3666 (end-of-line)(point)))))
3667 (allout-flag-current-subtree ?\r)
3668 (goto-char from)
3669 (if (and (= orig-eol (progn (goto-char orig-eol)
3670 (end-of-line)
3671 (point)))
3672 (not just-close)
3673 ;; Structure didn't change - try hiding current level:
3674 (goto-char from)
3675 (if (allout-up-current-level 1 t)
3677 (goto-char 0)
3678 (let ((msg
3679 "Top-level topic already closed - closing siblings..."))
3680 (message msg)
3681 (allout-expose-topic '(0 :))
3682 (message (concat msg " Done.")))
3683 nil)
3684 (/= (allout-recent-depth) 0))
3685 (allout-hide-current-subtree))
3686 (goto-char from)))
3687 ;;;_ > allout-show-current-branches ()
3688 (defun allout-show-current-branches ()
3689 "Show all subheadings of this heading, but not their bodies."
3690 (interactive)
3691 (beginning-of-line)
3692 (allout-show-children t))
3693 ;;;_ > allout-hide-current-leaves ()
3694 (defun allout-hide-current-leaves ()
3695 "Hide the bodies of the current topic and all its offspring."
3696 (interactive)
3697 (allout-back-to-current-heading)
3698 (allout-hide-region-body (point) (progn (allout-end-of-current-subtree)
3699 (point))))
3701 ;;;_ - Region and beyond
3702 ;;;_ > allout-show-all ()
3703 (defun allout-show-all ()
3704 "Show all of the text in the buffer."
3705 (interactive)
3706 (message "Exposing entire buffer...")
3707 (allout-flag-region (point-min) (point-max) ?\n)
3708 (message "Exposing entire buffer... Done."))
3709 ;;;_ > allout-hide-bodies ()
3710 (defun allout-hide-bodies ()
3711 "Hide all of buffer except headings."
3712 (interactive)
3713 (allout-hide-region-body (point-min) (point-max)))
3714 ;;;_ > allout-hide-region-body (start end)
3715 (defun allout-hide-region-body (start end)
3716 "Hide all body lines in the region, but not headings."
3717 (save-excursion
3718 (save-restriction
3719 (narrow-to-region start end)
3720 (goto-char (point-min))
3721 (while (not (eobp))
3722 (allout-flag-region (point)
3723 (progn (allout-pre-next-preface) (point)) ?\r)
3724 (if (not (eobp))
3725 (forward-char
3726 (if (looking-at "[\n\r][\n\r]")
3727 2 1)))))))
3729 ;;;_ > allout-expose-topic (spec)
3730 (defun allout-expose-topic (spec)
3731 "Apply exposure specs to successive outline topic items.
3733 Use the more convenient frontend, `allout-new-exposure', if you don't
3734 need evaluation of the arguments, or even better, the `allout-layout'
3735 variable-keyed mode-activation/auto-exposure feature of allout outline
3736 mode. See the respective documentation strings for more details.
3738 Cursor is left at start position.
3740 SPEC is either a number or a list.
3742 Successive specs on a list are applied to successive sibling topics.
3744 A simple spec \(either a number, one of a few symbols, or the null
3745 list) dictates the exposure for the corresponding topic.
3747 Non-null lists recursively designate exposure specs for respective
3748 subtopics of the current topic.
3750 The `:' repeat spec is used to specify exposure for any number of
3751 successive siblings, up to the trailing ones for which there are
3752 explicit specs following the `:'.
3754 Simple (numeric and null-list) specs are interpreted as follows:
3756 Numbers indicate the relative depth to open the corresponding topic.
3757 - negative numbers force the topic to be closed before opening to the
3758 absolute value of the number, so all siblings are open only to
3759 that level.
3760 - positive numbers open to the relative depth indicated by the
3761 number, but do not force already opened subtopics to be closed.
3762 - 0 means to close topic - hide all offspring.
3763 : - `repeat'
3764 apply prior element to all siblings at current level, *up to*
3765 those siblings that would be covered by specs following the `:'
3766 on the list. Ie, apply to all topics at level but the last
3767 ones. \(Only first of multiple colons at same level is
3768 respected - subsequent ones are discarded.)
3769 * - completely opens the topic, including bodies.
3770 + - shows all the sub headers, but not the bodies
3771 - - exposes the body of the corresponding topic.
3773 Examples:
3774 \(allout-expose-topic '(-1 : 0))
3775 Close this and all following topics at current level, exposing
3776 only their immediate children, but close down the last topic
3777 at this current level completely.
3778 \(allout-expose-topic '(-1 () : 1 0))
3779 Close current topic so only the immediate subtopics are shown;
3780 show the children in the second to last topic, and completely
3781 close the last one.
3782 \(allout-expose-topic '(-2 : -1 *))
3783 Expose children and grandchildren of all topics at current
3784 level except the last two; expose children of the second to
3785 last and completely open the last one."
3787 (interactive "xExposure spec: ")
3788 (if (not (listp spec))
3790 (let ((depth (allout-depth))
3791 (max-pos 0)
3792 prev-elem curr-elem
3793 stay done
3794 snug-back
3796 (while spec
3797 (setq prev-elem curr-elem
3798 curr-elem (car spec)
3799 spec (cdr spec))
3800 (cond ; Do current element:
3801 ((null curr-elem) nil)
3802 ((symbolp curr-elem)
3803 (cond ((eq curr-elem '*) (allout-show-current-subtree)
3804 (if (> allout-recent-end-of-subtree max-pos)
3805 (setq max-pos allout-recent-end-of-subtree)))
3806 ((eq curr-elem '+) (allout-show-current-branches)
3807 (if (> allout-recent-end-of-subtree max-pos)
3808 (setq max-pos allout-recent-end-of-subtree)))
3809 ((eq curr-elem '-) (allout-show-current-entry))
3810 ((eq curr-elem ':)
3811 (setq stay t)
3812 ;; Expand the `repeat' spec to an explicit version,
3813 ;; w.r.t. remaining siblings:
3814 (let ((residue ; = # of sibs not covered by remaining spec
3815 ;; Dang - could be nice to make use of the chart, sigh:
3816 (- (length (allout-chart-siblings))
3817 (length spec))))
3818 (if (< 0 residue)
3819 ;; Some residue - cover it with prev-elem:
3820 (setq spec (append (make-list residue prev-elem)
3821 spec)))))))
3822 ((numberp curr-elem)
3823 (if (and (>= 0 curr-elem) (allout-visible-p))
3824 (save-excursion (allout-hide-current-subtree t)
3825 (if (> 0 curr-elem)
3827 (if (> allout-recent-end-of-subtree max-pos)
3828 (setq max-pos
3829 allout-recent-end-of-subtree)))))
3830 (if (> (abs curr-elem) 0)
3831 (progn (allout-show-children (abs curr-elem))
3832 (if (> allout-recent-end-of-subtree max-pos)
3833 (setq max-pos allout-recent-end-of-subtree)))))
3834 ((listp curr-elem)
3835 (if (allout-descend-to-depth (1+ depth))
3836 (let ((got (allout-expose-topic curr-elem)))
3837 (if (and got (> got max-pos)) (setq max-pos got))))))
3838 (cond (stay (setq stay nil))
3839 ((listp (car spec)) nil)
3840 ((> max-pos (point))
3841 ;; Capitalize on max-pos state to get us nearer next sibling:
3842 (progn (goto-char (min (point-max) max-pos))
3843 (allout-next-heading)))
3844 ((allout-next-sibling depth))))
3845 max-pos)))
3846 ;;;_ > allout-old-expose-topic (spec &rest followers)
3847 (defun allout-old-expose-topic (spec &rest followers)
3848 "Dictate wholesale exposure scheme for current topic, according to SPEC.
3850 SPEC is either a number or a list. Optional successive args
3851 dictate exposure for subsequent siblings of current topic.
3853 A simple spec (either a number, a special symbol, or the null list)
3854 dictates the overall exposure for a topic. Non null lists are
3855 composite specs whose first element dictates the overall exposure for
3856 a topic, with the subsequent elements in the list interpreted as specs
3857 that dictate the exposure for the successive offspring of the topic.
3859 Simple (numeric and null-list) specs are interpreted as follows:
3861 - Numbers indicate the relative depth to open the corresponding topic:
3862 - negative numbers force the topic to be close before opening to the
3863 absolute value of the number.
3864 - positive numbers just open to the relative depth indicated by the number.
3865 - 0 just closes
3866 - `*' completely opens the topic, including bodies.
3867 - `+' shows all the sub headers, but not the bodies
3868 - `-' exposes the body and immediate offspring of the corresponding topic.
3870 If the spec is a list, the first element must be a number, which
3871 dictates the exposure depth of the topic as a whole. Subsequent
3872 elements of the list are nested SPECs, dictating the specific exposure
3873 for the corresponding offspring of the topic.
3875 Optional FOLLOWERS arguments dictate exposure for succeeding siblings."
3877 (interactive "xExposure spec: ")
3878 (let ((depth (allout-current-depth))
3879 done
3880 max-pos)
3881 (cond ((null spec) nil)
3882 ((symbolp spec)
3883 (if (eq spec '*) (allout-show-current-subtree))
3884 (if (eq spec '+) (allout-show-current-branches))
3885 (if (eq spec '-) (allout-show-current-entry)))
3886 ((numberp spec)
3887 (if (>= 0 spec)
3888 (save-excursion (allout-hide-current-subtree t)
3889 (end-of-line)
3890 (if (or (not max-pos)
3891 (> (point) max-pos))
3892 (setq max-pos (point)))
3893 (if (> 0 spec)
3894 (setq spec (* -1 spec)))))
3895 (if (> spec 0)
3896 (allout-show-children spec)))
3897 ((listp spec)
3898 ;(let ((got (allout-old-expose-topic (car spec))))
3899 ; (if (and got (or (not max-pos) (> got max-pos)))
3900 ; (setq max-pos got)))
3901 (let ((new-depth (+ (allout-current-depth) 1))
3902 got)
3903 (setq max-pos (allout-old-expose-topic (car spec)))
3904 (setq spec (cdr spec))
3905 (if (and spec
3906 (allout-descend-to-depth new-depth)
3907 (not (allout-hidden-p)))
3908 (progn (setq got (apply 'allout-old-expose-topic spec))
3909 (if (and got (or (not max-pos) (> got max-pos)))
3910 (setq max-pos got)))))))
3911 (while (and followers
3912 (progn (if (and max-pos (< (point) max-pos))
3913 (progn (goto-char max-pos)
3914 (setq max-pos nil)))
3915 (end-of-line)
3916 (allout-next-sibling depth)))
3917 (allout-old-expose-topic (car followers))
3918 (setq followers (cdr followers)))
3919 max-pos))
3920 (make-obsolete 'allout-old-expose-topic
3921 "use `allout-expose-topic' (with different schema format) instead."
3922 "19.23")
3923 ;;;_ > allout-new-exposure '()
3924 (defmacro allout-new-exposure (&rest spec)
3925 "Literal frontend for `allout-expose-topic', doesn't evaluate arguments.
3926 Some arguments that would need to be quoted in `allout-expose-topic'
3927 need not be quoted in `allout-new-exposure'.
3929 Cursor is left at start position.
3931 Examples:
3932 \(allout-new-exposure (-1 () () () 1) 0)
3933 Close current topic at current level so only the immediate
3934 subtopics are shown, except also show the children of the
3935 third subtopic; and close the next topic at the current level.
3936 \(allout-new-exposure : -1 0)
3937 Close all topics at current level to expose only their
3938 immediate children, except for the last topic at the current
3939 level, in which even its immediate children are hidden.
3940 \(allout-new-exposure -2 : -1 *)
3941 Expose children and grandchildren of first topic at current
3942 level, and expose children of subsequent topics at current
3943 level *except* for the last, which should be opened completely."
3944 (list 'save-excursion
3945 '(if (not (or (allout-goto-prefix)
3946 (allout-next-heading)))
3947 (error "allout-new-exposure: Can't find any outline topics"))
3948 (list 'allout-expose-topic (list 'quote spec))))
3950 ;;;_ #7 Systematic outline presentation - copying, printing, flattening
3952 ;;;_ - Mapping and processing of topics
3953 ;;;_ ( See also Subtree Charting, in Navigation code.)
3954 ;;;_ > allout-stringify-flat-index (flat-index)
3955 (defun allout-stringify-flat-index (flat-index &optional context)
3956 "Convert list representing section/subsection/... to document string.
3958 Optional arg CONTEXT indicates interior levels to include."
3959 (let ((delim ".")
3960 result
3961 numstr
3962 (context-depth (or (and context 2) 1)))
3963 ;; Take care of the explicit context:
3964 (while (> context-depth 0)
3965 (setq numstr (int-to-string (car flat-index))
3966 flat-index (cdr flat-index)
3967 result (if flat-index
3968 (cons delim (cons numstr result))
3969 (cons numstr result))
3970 context-depth (if flat-index (1- context-depth) 0)))
3971 (setq delim " ")
3972 ;; Take care of the indentation:
3973 (if flat-index
3974 (progn
3975 (while flat-index
3976 (setq result
3977 (cons delim
3978 (cons (make-string
3979 (1+ (truncate (if (zerop (car flat-index))
3981 (log10 (car flat-index)))))
3983 result)))
3984 (setq flat-index (cdr flat-index)))
3985 ;; Dispose of single extra delim:
3986 (setq result (cdr result))))
3987 (apply 'concat result)))
3988 ;;;_ > allout-stringify-flat-index-plain (flat-index)
3989 (defun allout-stringify-flat-index-plain (flat-index)
3990 "Convert list representing section/subsection/... to document string."
3991 (let ((delim ".")
3992 result)
3993 (while flat-index
3994 (setq result (cons (int-to-string (car flat-index))
3995 (if result
3996 (cons delim result))))
3997 (setq flat-index (cdr flat-index)))
3998 (apply 'concat result)))
3999 ;;;_ > allout-stringify-flat-index-indented (flat-index)
4000 (defun allout-stringify-flat-index-indented (flat-index)
4001 "Convert list representing section/subsection/... to document string."
4002 (let ((delim ".")
4003 result
4004 numstr)
4005 ;; Take care of the explicit context:
4006 (setq numstr (int-to-string (car flat-index))
4007 flat-index (cdr flat-index)
4008 result (if flat-index
4009 (cons delim (cons numstr result))
4010 (cons numstr result)))
4011 (setq delim " ")
4012 ;; Take care of the indentation:
4013 (if flat-index
4014 (progn
4015 (while flat-index
4016 (setq result
4017 (cons delim
4018 (cons (make-string
4019 (1+ (truncate (if (zerop (car flat-index))
4021 (log10 (car flat-index)))))
4023 result)))
4024 (setq flat-index (cdr flat-index)))
4025 ;; Dispose of single extra delim:
4026 (setq result (cdr result))))
4027 (apply 'concat result)))
4028 ;;;_ > allout-listify-exposed (&optional start end format)
4029 (defun allout-listify-exposed (&optional start end format)
4031 "Produce a list representing exposed topics in current region.
4033 This list can then be used by `allout-process-exposed' to manipulate
4034 the subject region.
4036 Optional START and END indicate bounds of region.
4038 optional arg, FORMAT, designates an alternate presentation form for
4039 the prefix:
4041 list - Present prefix as numeric section.subsection..., starting with
4042 section indicated by the list, innermost nesting first.
4043 `indent' \(symbol) - Convert header prefixes to all white space,
4044 except for distinctive bullets.
4046 The elements of the list produced are lists that represents a topic
4047 header and body. The elements of that list are:
4049 - a number representing the depth of the topic,
4050 - a string representing the header-prefix, including trailing whitespace and
4051 bullet.
4052 - a string representing the bullet character,
4053 - and a series of strings, each containing one line of the exposed
4054 portion of the topic entry."
4056 (interactive "r")
4057 (save-excursion
4058 (let*
4059 ;; state vars:
4060 (strings prefix pad result depth new-depth out gone-out bullet beg
4061 next done)
4063 (goto-char start)
4064 (beginning-of-line)
4065 ;; Goto initial topic, and register preceeding stuff, if any:
4066 (if (> (allout-goto-prefix) start)
4067 ;; First topic follows beginning point - register preliminary stuff:
4068 (setq result (list (list 0 "" nil
4069 (buffer-substring start (1- (point)))))))
4070 (while (and (not done)
4071 (not (eobp)) ; Loop until we've covered the region.
4072 (not (> (point) end)))
4073 (setq depth (allout-recent-depth) ; Current topics depth,
4074 bullet (allout-recent-bullet) ; ... bullet,
4075 prefix (allout-recent-prefix)
4076 beg (progn (allout-end-of-prefix t) (point))) ; and beginning.
4077 (setq done ; The boundary for the current topic:
4078 (not (allout-next-visible-heading 1)))
4079 (setq new-depth (allout-recent-depth))
4080 (setq gone-out out
4081 out (< new-depth depth))
4082 (beginning-of-line)
4083 (setq next (point))
4084 (goto-char beg)
4085 (setq strings nil)
4086 (while (> next (point)) ; Get all the exposed text in
4087 (setq strings
4088 (cons (buffer-substring
4090 ;To hidden text or end of line:
4091 (progn
4092 (search-forward "\r"
4093 (save-excursion (end-of-line)
4094 (point))
4096 (if (= (preceding-char) ?\r)
4097 (1- (point))
4098 (point))))
4099 strings))
4100 (if (< (point) next) ; Resume from after hid text, if any.
4101 (forward-line 1))
4102 (setq beg (point)))
4103 ;; Accumulate list for this topic:
4104 (setq strings (nreverse strings))
4105 (setq result
4106 (cons
4107 (if format
4108 (let ((special (if (string-match
4109 (regexp-quote bullet)
4110 allout-distinctive-bullets-string)
4111 bullet)))
4112 (cond ((listp format)
4113 (list depth
4114 (if allout-abbreviate-flattened-numbering
4115 (allout-stringify-flat-index format
4116 gone-out)
4117 (allout-stringify-flat-index-plain
4118 format))
4119 strings
4120 special))
4121 ((eq format 'indent)
4122 (if special
4123 (list depth
4124 (concat (make-string (1+ depth) ? )
4125 (substring prefix -1))
4126 strings)
4127 (list depth
4128 (make-string depth ? )
4129 strings)))
4130 (t (error "allout-listify-exposed: %s %s"
4131 "invalid format" format))))
4132 (list depth prefix strings))
4133 result))
4134 ;; Reasses format, if any:
4135 (if (and format (listp format))
4136 (cond ((= new-depth depth)
4137 (setq format (cons (1+ (car format))
4138 (cdr format))))
4139 ((> new-depth depth) ; descending - assume by 1:
4140 (setq format (cons 1 format)))
4142 ; Pop the residue:
4143 (while (< new-depth depth)
4144 (setq format (cdr format))
4145 (setq depth (1- depth)))
4146 ; And increment the current one:
4147 (setq format
4148 (cons (1+ (or (car format)
4149 -1))
4150 (cdr format)))))))
4151 ;; Put the list with first at front, to last at back:
4152 (nreverse result))))
4153 ;;;_ > allout-process-exposed (&optional func from to frombuf
4154 ;;; tobuf format)
4155 (defun allout-process-exposed (&optional func from to frombuf tobuf
4156 format start-num)
4157 "Map function on exposed parts of current topic; results to another buffer.
4159 Apply FUNC to exposed portions FROM position TO position in buffer
4160 FROMBUF to buffer TOBUF. Sixth optional arg, FORMAT, designates an
4161 alternate presentation form:
4163 `flat' - Present prefix as numeric section.subsection..., starting with
4164 section indicated by the start-num, innermost nesting first.
4165 X`flat-indented' - Prefix is like `flat' for first topic at each
4166 X level, but subsequent topics have only leaf topic
4167 X number, padded with blanks to line up with first.
4168 `indent' \(symbol) - Convert header prefixes to all white space,
4169 except for distinctive bullets.
4171 Defaults:
4172 FUNC: `allout-insert-listified'
4173 FROM: region start, if region active, else start of buffer
4174 TO: region end, if region active, else end of buffer
4175 FROMBUF: current buffer
4176 TOBUF: buffer name derived: \"*current-buffer-name exposed*\"
4177 FORMAT: nil"
4179 ; Resolve arguments,
4180 ; defaulting if necessary:
4181 (if (not func) (setq func 'allout-insert-listified))
4182 (if (not (and from to))
4183 (if (my-region-active-p)
4184 (setq from (region-beginning) to (region-end))
4185 (setq from (point-min) to (point-max))))
4186 (if frombuf
4187 (if (not (bufferp frombuf))
4188 ;; Specified but not a buffer - get it:
4189 (let ((got (get-buffer frombuf)))
4190 (if (not got)
4191 (error (concat "allout-process-exposed: source buffer "
4192 frombuf
4193 " not found."))
4194 (setq frombuf got))))
4195 ;; not specified - default it:
4196 (setq frombuf (current-buffer)))
4197 (if tobuf
4198 (if (not (bufferp tobuf))
4199 (setq tobuf (get-buffer-create tobuf)))
4200 ;; not specified - default it:
4201 (setq tobuf (concat "*" (buffer-name frombuf) " exposed*")))
4202 (if (listp format)
4203 (nreverse format))
4205 (let* ((listified
4206 (progn (set-buffer frombuf)
4207 (allout-listify-exposed from to format))))
4208 (set-buffer tobuf)
4209 (mapcar func listified)
4210 (pop-to-buffer tobuf)))
4212 ;;;_ - Copy exposed
4213 ;;;_ > allout-insert-listified (listified)
4214 (defun allout-insert-listified (listified)
4215 "Insert contents of listified outline portion in current buffer.
4217 LISTIFIED is a list representing each topic header and body:
4219 \`(depth prefix text)'
4223 \`(depth prefix text bullet-plus)'
4225 If `bullet-plus' is specified, it is inserted just after the entire prefix."
4226 (setq listified (cdr listified))
4227 (let ((prefix (prog1
4228 (car listified)
4229 (setq listified (cdr listified))))
4230 (text (prog1
4231 (car listified)
4232 (setq listified (cdr listified))))
4233 (bullet-plus (car listified)))
4234 (insert prefix)
4235 (if bullet-plus (insert (concat " " bullet-plus)))
4236 (while text
4237 (insert (car text))
4238 (if (setq text (cdr text))
4239 (insert "\n")))
4240 (insert "\n")))
4241 ;;;_ > allout-copy-exposed-to-buffer (&optional arg tobuf format)
4242 (defun allout-copy-exposed-to-buffer (&optional arg tobuf format)
4243 "Duplicate exposed portions of current outline to another buffer.
4245 Other buffer has current buffers name with \" exposed\" appended to it.
4247 With repeat count, copy the exposed parts of only the current topic.
4249 Optional second arg TOBUF is target buffer name.
4251 Optional third arg FORMAT, if non-nil, symbolically designates an
4252 alternate presentation format for the outline:
4254 `flat' - Convert topic header prefixes to numeric
4255 section.subsection... identifiers.
4256 `indent' - Convert header prefixes to all white space, except for
4257 distinctive bullets.
4258 `indent-flat' - The best of both - only the first of each level has
4259 the full path, the rest have only the section number
4260 of the leaf, preceded by the right amount of indentation."
4262 (interactive "P")
4263 (if (not tobuf)
4264 (setq tobuf (get-buffer-create (concat "*" (buffer-name) " exposed*"))))
4265 (let* ((start-pt (point))
4266 (beg (if arg (allout-back-to-current-heading) (point-min)))
4267 (end (if arg (allout-end-of-current-subtree) (point-max)))
4268 (buf (current-buffer))
4269 (start-list ()))
4270 (if (eq format 'flat)
4271 (setq format (if arg (save-excursion
4272 (goto-char beg)
4273 (allout-topic-flat-index))
4274 '(1))))
4275 (save-excursion (set-buffer tobuf)(erase-buffer))
4276 (allout-process-exposed 'allout-insert-listified
4279 (current-buffer)
4280 tobuf
4281 format start-list)
4282 (goto-char (point-min))
4283 (pop-to-buffer buf)
4284 (goto-char start-pt)))
4285 ;;;_ > allout-flatten-exposed-to-buffer (&optional arg tobuf)
4286 (defun allout-flatten-exposed-to-buffer (&optional arg tobuf)
4287 "Present numeric outline of outline's exposed portions in another buffer.
4289 The resulting outline is not compatible with outline mode - use
4290 `allout-copy-exposed-to-buffer' if you want that.
4292 Use `allout-indented-exposed-to-buffer' for indented presentation.
4294 With repeat count, copy the exposed portions of only current topic.
4296 Other buffer has current buffer's name with \" exposed\" appended to
4297 it, unless optional second arg TOBUF is specified, in which case it is
4298 used verbatim."
4299 (interactive "P")
4300 (allout-copy-exposed-to-buffer arg tobuf 'flat))
4301 ;;;_ > allout-indented-exposed-to-buffer (&optional arg tobuf)
4302 (defun allout-indented-exposed-to-buffer (&optional arg tobuf)
4303 "Present indented outline of outline's exposed portions in another buffer.
4305 The resulting outline is not compatible with outline mode - use
4306 `allout-copy-exposed-to-buffer' if you want that.
4308 Use `allout-flatten-exposed-to-buffer' for numeric sectional presentation.
4310 With repeat count, copy the exposed portions of only current topic.
4312 Other buffer has current buffer's name with \" exposed\" appended to
4313 it, unless optional second arg TOBUF is specified, in which case it is
4314 used verbatim."
4315 (interactive "P")
4316 (allout-copy-exposed-to-buffer arg tobuf 'indent))
4318 ;;;_ - LaTeX formatting
4319 ;;;_ > allout-latex-verb-quote (string &optional flow)
4320 (defun allout-latex-verb-quote (string &optional flow)
4321 "Return copy of STRING for literal reproduction across LaTeX processing.
4322 Expresses the original characters \(including carriage returns) of the
4323 string across LaTeX processing."
4324 (mapconcat (function
4325 (lambda (char)
4326 (cond ((memq char '(?\\ ?$ ?% ?# ?& ?{ ?} ?_ ?^ ?- ?*))
4327 (concat "\\char" (number-to-string char) "{}"))
4328 ((= char ?\n) "\\\\")
4329 (t (char-to-string char)))))
4330 string
4331 ""))
4332 ;;;_ > allout-latex-verbatim-quote-curr-line ()
4333 (defun allout-latex-verbatim-quote-curr-line ()
4334 "Express line for exact \(literal) representation across LaTeX processing.
4336 Adjust line contents so it is unaltered \(from the original line)
4337 across LaTeX processing, within the context of a `verbatim'
4338 environment. Leaves point at the end of the line."
4339 (beginning-of-line)
4340 (let ((beg (point))
4341 (end (progn (end-of-line)(point))))
4342 (goto-char beg)
4343 (while (re-search-forward "\\\\"
4344 ;;"\\\\\\|\\{\\|\\}\\|\\_\\|\\$\\|\\\"\\|\\&\\|\\^\\|\\-\\|\\*\\|#"
4345 end ; bounded by end-of-line
4346 1) ; no matches, move to end & return nil
4347 (goto-char (match-beginning 0))
4348 (insert "\\")
4349 (setq end (1+ end))
4350 (goto-char (1+ (match-end 0))))))
4351 ;;;_ > allout-insert-latex-header (buffer)
4352 (defun allout-insert-latex-header (buffer)
4353 "Insert initial LaTeX commands at point in BUFFER."
4354 ;; Much of this is being derived from the stuff in appendix of E in
4355 ;; the TeXBook, pg 421.
4356 (set-buffer buffer)
4357 (let ((doc-style (format "\n\\documentstyle{%s}\n"
4358 "report"))
4359 (page-numbering (if allout-number-pages
4360 "\\pagestyle{empty}\n"
4361 ""))
4362 (linesdef (concat "\\def\\beginlines{"
4363 "\\par\\begingroup\\nobreak\\medskip"
4364 "\\parindent=0pt\n"
4365 " \\kern1pt\\nobreak \\obeylines \\obeyspaces "
4366 "\\everypar{\\strut}}\n"
4367 "\\def\\endlines{"
4368 "\\kern1pt\\endgroup\\medbreak\\noindent}\n"))
4369 (titlecmd (format "\\newcommand{\\titlecmd}[1]{{%s #1}}\n"
4370 allout-title-style))
4371 (labelcmd (format "\\newcommand{\\labelcmd}[1]{{%s #1}}\n"
4372 allout-label-style))
4373 (headlinecmd (format "\\newcommand{\\headlinecmd}[1]{{%s #1}}\n"
4374 allout-head-line-style))
4375 (bodylinecmd (format "\\newcommand{\\bodylinecmd}[1]{{%s #1}}\n"
4376 allout-body-line-style))
4377 (setlength (format "%s%s%s%s"
4378 "\\newlength{\\stepsize}\n"
4379 "\\setlength{\\stepsize}{"
4380 allout-indent
4381 "}\n"))
4382 (oneheadline (format "%s%s%s%s%s%s%s"
4383 "\\newcommand{\\OneHeadLine}[3]{%\n"
4384 "\\noindent%\n"
4385 "\\hspace*{#2\\stepsize}%\n"
4386 "\\labelcmd{#1}\\hspace*{.2cm}"
4387 "\\headlinecmd{#3}\\\\["
4388 allout-line-skip
4389 "]\n}\n"))
4390 (onebodyline (format "%s%s%s%s%s%s"
4391 "\\newcommand{\\OneBodyLine}[2]{%\n"
4392 "\\noindent%\n"
4393 "\\hspace*{#1\\stepsize}%\n"
4394 "\\bodylinecmd{#2}\\\\["
4395 allout-line-skip
4396 "]\n}\n"))
4397 (begindoc "\\begin{document}\n\\begin{center}\n")
4398 (title (format "%s%s%s%s"
4399 "\\titlecmd{"
4400 (allout-latex-verb-quote (if allout-title
4401 (condition-case err
4402 (eval allout-title)
4403 ('error "<unnamed buffer>"))
4404 "Unnamed Outline"))
4405 "}\n"
4406 "\\end{center}\n\n"))
4407 (hsize "\\hsize = 7.5 true in\n")
4408 (hoffset "\\hoffset = -1.5 true in\n")
4409 (vspace "\\vspace{.1cm}\n\n"))
4410 (insert (concat doc-style
4411 page-numbering
4412 titlecmd
4413 labelcmd
4414 headlinecmd
4415 bodylinecmd
4416 setlength
4417 oneheadline
4418 onebodyline
4419 begindoc
4420 title
4421 hsize
4422 hoffset
4423 vspace)
4425 ;;;_ > allout-insert-latex-trailer (buffer)
4426 (defun allout-insert-latex-trailer (buffer)
4427 "Insert concluding LaTeX commands at point in BUFFER."
4428 (set-buffer buffer)
4429 (insert "\n\\end{document}\n"))
4430 ;;;_ > allout-latexify-one-item (depth prefix bullet text)
4431 (defun allout-latexify-one-item (depth prefix bullet text)
4432 "Insert LaTeX commands for formatting one outline item.
4434 Args are the topics numeric DEPTH, the header PREFIX lead string, the
4435 BULLET string, and a list of TEXT strings for the body."
4436 (let* ((head-line (if text (car text)))
4437 (body-lines (cdr text))
4438 (curr-line)
4439 body-content bop)
4440 ; Do the head line:
4441 (insert (concat "\\OneHeadLine{\\verb\1 "
4442 (allout-latex-verb-quote bullet)
4443 "\1}{"
4444 depth
4445 "}{\\verb\1 "
4446 (if head-line
4447 (allout-latex-verb-quote head-line)
4449 "\1}\n"))
4450 (if (not body-lines)
4452 ;;(insert "\\beginlines\n")
4453 (insert "\\begin{verbatim}\n")
4454 (while body-lines
4455 (setq curr-line (car body-lines))
4456 (if (and (not body-content)
4457 (not (string-match "^\\s-*$" curr-line)))
4458 (setq body-content t))
4459 ; Mangle any occurrences of
4460 ; "\end{verbatim}" in text,
4461 ; it's special:
4462 (if (and body-content
4463 (setq bop (string-match "\\end{verbatim}" curr-line)))
4464 (setq curr-line (concat (substring curr-line 0 bop)
4466 (substring curr-line bop))))
4467 ;;(insert "|" (car body-lines) "|")
4468 (insert curr-line)
4469 (allout-latex-verbatim-quote-curr-line)
4470 (insert "\n")
4471 (setq body-lines (cdr body-lines)))
4472 (if body-content
4473 (setq body-content nil)
4474 (forward-char -1)
4475 (insert "\\ ")
4476 (forward-char 1))
4477 ;;(insert "\\endlines\n")
4478 (insert "\\end{verbatim}\n")
4480 ;;;_ > allout-latexify-exposed (arg &optional tobuf)
4481 (defun allout-latexify-exposed (arg &optional tobuf)
4482 "Format current topics exposed portions to TOBUF for LaTeX processing.
4483 TOBUF defaults to a buffer named the same as the current buffer, but
4484 with \"*\" prepended and \" latex-formed*\" appended.
4486 With repeat count, copy the exposed portions of entire buffer."
4488 (interactive "P")
4489 (if (not tobuf)
4490 (setq tobuf
4491 (get-buffer-create (concat "*" (buffer-name) " latexified*"))))
4492 (let* ((start-pt (point))
4493 (beg (if arg (point-min) (allout-back-to-current-heading)))
4494 (end (if arg (point-max) (allout-end-of-current-subtree)))
4495 (buf (current-buffer)))
4496 (set-buffer tobuf)
4497 (erase-buffer)
4498 (allout-insert-latex-header tobuf)
4499 (goto-char (point-max))
4500 (allout-process-exposed 'allout-latexify-one-item
4504 tobuf)
4505 (goto-char (point-max))
4506 (allout-insert-latex-trailer tobuf)
4507 (goto-char (point-min))
4508 (pop-to-buffer buf)
4509 (goto-char start-pt)))
4511 ;;;_ #8 miscellaneous
4512 ;;;_ > allout-mark-topic ()
4513 (defun allout-mark-topic ()
4514 "Put the region around topic currently containing point."
4515 (interactive)
4516 (beginning-of-line)
4517 (allout-goto-prefix)
4518 (push-mark (point))
4519 (allout-end-of-current-subtree)
4520 (exchange-point-and-mark))
4521 ;;;_ > outlineify-sticky ()
4522 ;; outlinify-sticky is correct spelling; provide this alias for sticklers:
4523 (defalias 'outlinify-sticky 'outlineify-sticky)
4524 (defun outlineify-sticky (&optional arg)
4525 "Activate outline mode and establish file var so it is started subsequently.
4527 See doc-string for `allout-layout' and `allout-init' for details on
4528 setup for auto-startup."
4530 (interactive "P")
4532 (allout-mode t)
4534 (save-excursion
4535 (goto-char (point-min))
4536 (if (looking-at allout-regexp)
4538 (allout-open-topic 2)
4539 (insert (concat "Dummy outline topic header - see"
4540 "`allout-mode' docstring: `^Hm'."))
4541 (forward-line 1)
4542 (goto-char (point-max))
4543 (open-line 1)
4544 (allout-open-topic 0)
4545 (insert "Local emacs vars.\n")
4546 (allout-open-topic 1)
4547 (insert "(`allout-layout' is for allout.el allout-mode)\n")
4548 (allout-open-topic 0)
4549 (insert "Local variables:\n")
4550 (allout-open-topic 0)
4551 (insert (format "allout-layout: %s\n"
4552 (or allout-layout
4553 '(-1 : 0))))
4554 (allout-open-topic 0)
4555 (insert "End:\n"))))
4556 ;;;_ > solicit-char-in-string (prompt string &optional do-defaulting)
4557 (defun solicit-char-in-string (prompt string &optional do-defaulting)
4558 "Solicit (with first arg PROMPT) choice of a character from string STRING.
4560 Optional arg DO-DEFAULTING indicates to accept empty input (CR)."
4562 (let ((new-prompt prompt)
4563 got)
4565 (while (not got)
4566 (message "%s" new-prompt)
4568 ;; We do our own reading here, so we can circumvent, eg, special
4569 ;; treatment for `?' character. (Oughta use minibuffer keymap instead.)
4570 (setq got
4571 (char-to-string (let ((cursor-in-echo-area nil)) (read-char))))
4573 (setq got
4574 (cond ((string-match (regexp-quote got) string) got)
4575 ((and do-defaulting (string= got "\r"))
4576 ;; Return empty string to default:
4578 ((string= got "\C-g") (signal 'quit nil))
4580 (setq new-prompt (concat prompt
4582 " ...pick from: "
4583 string
4584 ""))
4585 nil))))
4586 ;; got something out of loop - return it:
4587 got)
4589 ;;;_ > regexp-sans-escapes (string)
4590 (defun regexp-sans-escapes (regexp &optional successive-backslashes)
4591 "Return a copy of REGEXP with all character escapes stripped out.
4593 Representations of actual backslashes - '\\\\\\\\' - are left as a
4594 single backslash.
4596 \(fn REGEXP)"
4597 ;; Optional arg SUCCESSIVE-BACKSLASHES is used internally for recursion.
4599 (if (string= regexp "")
4601 ;; Set successive-backslashes to number if current char is
4602 ;; backslash, or else to nil:
4603 (setq successive-backslashes
4604 (if (= (aref regexp 0) ?\\)
4605 (if successive-backslashes (1+ successive-backslashes) 1)
4606 nil))
4607 (if (or (not successive-backslashes) (= 2 successive-backslashes))
4608 ;; Include first char:
4609 (concat (substring regexp 0 1)
4610 (regexp-sans-escapes (substring regexp 1)))
4611 ;; Exclude first char, but maintain count:
4612 (regexp-sans-escapes (substring regexp 1) successive-backslashes))))
4613 ;;;_ > my-region-active-p ()
4614 (defmacro my-region-active-p ()
4615 (if (fboundp 'region-active-p)
4616 '(region-active-p)
4617 'mark-active))
4618 ;;;_ - add-hook definition for divergent emacsen
4619 ;;;_ > add-hook (hook function &optional append)
4620 (if (not (fboundp 'add-hook))
4621 (defun add-hook (hook function &optional append)
4622 "Add to the value of HOOK the function FUNCTION unless already present.
4623 \(It becomes the first hook on the list unless optional APPEND is non-nil, in
4624 which case it becomes the last). HOOK should be a symbol, and FUNCTION may be
4625 any valid function. HOOK's value should be a list of functions, not a single
4626 function. If HOOK is void, it is first set to nil."
4627 (or (boundp hook) (set hook nil))
4628 (or (if (consp function)
4629 ;; Clever way to tell whether a given lambda-expression
4630 ;; is equal to anything in the hook.
4631 (let ((tail (assoc (cdr function) (symbol-value hook))))
4632 (equal function tail))
4633 (memq function (symbol-value hook)))
4634 (set hook
4635 (if append
4636 (nconc (symbol-value hook) (list function))
4637 (cons function (symbol-value hook)))))))
4638 ;;;_ : my-mark-marker to accommodate divergent emacsen:
4639 (defun my-mark-marker (&optional force buffer)
4640 "Accommodate the different signature for `mark-marker' across Emacsen.
4642 XEmacs takes two optional args, while GNU Emacs does not,
4643 so pass them along when appropriate."
4644 (if (featurep 'xemacs)
4645 (mark-marker force buffer)
4646 (mark-marker)))
4648 ;;;_ #9 Under development
4649 ;;;_ > allout-bullet-isearch (&optional bullet)
4650 (defun allout-bullet-isearch (&optional bullet)
4651 "Isearch \(regexp) for topic with bullet BULLET."
4652 (interactive)
4653 (if (not bullet)
4654 (setq bullet (solicit-char-in-string
4655 "ISearch for topic with bullet: "
4656 (regexp-sans-escapes allout-bullets-string))))
4658 (let ((isearch-regexp t)
4659 (isearch-string (concat "^"
4660 allout-header-prefix
4661 "[ \t]*"
4662 bullet)))
4663 (isearch-repeat 'forward)
4664 (isearch-mode t)))
4665 ;;;_ ? Re hooking up with isearch - use isearch-op-fun rather than
4666 ;;; wrapping the isearch functions.
4668 ;;;_* Local emacs vars.
4669 ;;; The following `allout-layout' local variable setting:
4670 ;;; - closes all topics from the first topic to just before the third-to-last,
4671 ;;; - shows the children of the third to last (config vars)
4672 ;;; - and the second to last (code section),
4673 ;;; - and closes the last topic (this local-variables section).
4674 ;;;Local variables:
4675 ;;;allout-layout: (0 : -1 -1 0)
4676 ;;;End:
4678 ;;; arch-tag: cf38fbc3-c044-450f-8bff-afed8ba5681c
4679 ;;; allout.el ends here