home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / modes / allout.el next >
Encoding:
Text File  |  1992-07-05  |  85.3 KB  |  2,103 lines

  1. ;
  2. Date: Sun, 5 Jul 92 11:49:45 EDT
  3. From: klm@cme.nist.gov (Ken Manheimer)
  4. Subject: 'allout.el' submission for LCD elisp archive directory
  5.  
  6. Around a half year ago i posted a package of extensions to emacs
  7. outline mode, which i called 'outext.el'.  In the interim i've
  8. developed some much more substantial extensions and revisions of the
  9. base outline mode, an essentially self contained package called
  10. 'allout.el'.  The code is attached below.
  11.  
  12. I released v 2.0 to the Usenet newsgroup gnu.emacs.sources a while
  13. back, and have gotten some bug fixes, which i've applied along with my
  14. own fixes developed in the interim.  I think i've got most if not all
  15. of the significant bugs, but i'm inundated at work and home, and doubt
  16. i'll have time to write up anything like an info file or even a
  17. detailed outline of the new features, so you'll have to make do for
  18. now with the 'outline-mode' and other functions' documentation
  19. strings, if you're interested in giving it a whirl.
  20.  
  21. Included below is, first, some exposition on the functionality of the
  22. package, then a patch to Kyle Jone's filladapt package, which must be
  23. applied in order to capitalize on filladapts features within the
  24. allout outline mode.  Below that (delimited by a "Cut Here" type line)
  25. is the allout.el code for the Emacs lisp archive.
  26.  
  27.  
  28. My original revisions included functions to create new topic templates
  29. relative to the current topic, shift entire subtrees to greater or
  30. lesser nesting depths, and use an alternate, more cogent bulleting
  31. scheme.  All of the functionality of the original outline mode was
  32. supported, including the old topic bulleting scheme.  (In fact, the
  33. code for the original outline version was used together with the new
  34. 'outext' code.)
  35.  
  36. This new release supports all those features in a more fleshed out
  37. way, plus:
  38.  
  39.   - Copy, cut, yank, and yank-pop of outline subtrees as units, with
  40.     automatic adjustment of the subtree depth to the depth of the new
  41.     location (if pasted into a blank topic template);
  42.  
  43.   - Adjustment of the bullet chars when you shift the depth of
  44.     subtrees, according to level;
  45.  
  46.   - "distinctive bullets", a specific user-configurable set of
  47.     characters which are immune to the level-change adjustments, so
  48.     special topic flags are retained across such shifts.  (See the
  49.     documentation string for 'outline-stylish-prefixes' for an
  50.     rudimentary example of the outline bulleting scheme with this and
  51.     the next elaborations.)
  52.  
  53.   - "numbered bullets", which automatically get numbers that indicate
  54.     how many siblings come between the topic and its parent, which
  55.     numbers are automatically reconciled upon the inclusion of new and
  56.     deletion of intervening siblings;
  57.  
  58.   - A substantial definition of outline terms and functions, in the
  59.     documentation string for the 'outline-mode' function;
  60.  
  61.   - A complete, self contained package, loaded instead of rather than
  62.     in addition to the distributed emacs outline code;
  63.  
  64.   - Clearer opportunities for outline code developement - rationalized
  65.     and reconciled function names, plus more thoroughly documented
  66.     code, for all outline functions.
  67.  
  68. There are two other, exceptionally nifty features, but they require
  69. use of other custom elisp software (both available from the lisp
  70. archives) in conjunction with allout:
  71.  
  72.   - Incremental search which dynamically exposes hidden outline bodies
  73.     when the search hits inside them, reconceals them if the search is
  74.     then continued past, or reveals the subtopics of all hidden
  75.     ancestors down to the target topic if the search is quit there.
  76.     You need to be using dan laliberte's 'isearch-mode' package for
  77.     this feature.
  78.  
  79.   - Automatically maintained hanging indentation on topic bodies,
  80.     which is accordingly adjusted when the depth of the topic is
  81.     changed.  You need to be using kyle jones 'filladapt' package to
  82.     get this feature.
  83.  
  84. I heartily recommend both of these packages in their own right, so i
  85. don't think you'll be losing anything to give them a try, and see what
  86. you it gets you in allout outline mode.
  87.  
  88. This is all the explanation i have time for now.  Alas, i doubt i'll
  89. get much time in the near future to write things up more thoroughly.
  90. However, if you find yourself really interested but you're perplexed
  91. by some feature or behavior, drop me an email-line and i'll see what i
  92. can do to help.
  93.  
  94. Cheers, 
  95.  
  96. Ken Manheimer
  97. klm@cme.nist.gov, 301 975-3539
  98.  
  99. 8<-------------------------- Cut Here -------------------------->8
  100.  
  101. As seems inevitable, i neglected to include some customizations you
  102. need to apply to the distributed (lisp archives) version of kyle
  103. jones' filladapt package, if you want allout to use it for hanging
  104. topic bodies.  I'm attaching below a diff of the distributed version
  105. (from the elisp archive - i believe it's as of Sep 89) to my modified
  106. one.
  107.  
  108. If i am recalling correctly, my changes amount to parameterizing
  109. hanging list prefixes so individual modes can define their own special
  110. ones, which is what allout does.  (I also extend the default hanging
  111. list regexps to include ':' colons.)
  112.  
  113. To apply the diffs,
  114.  
  115.     patch filladapt.el < thisMessage
  116.  
  117. I hope people find allout as useful as i have.  It's more than
  118. returned the time i invested, enabling me to keep track of a lot more
  119. than i previously could.  This can be a lifesaver in system
  120. management/support type jobs, and probably would be in a lot of
  121. others...
  122.  
  123. Ken again.
  124. klm@cme.nist.gov, 301 975-3539
  125.  
  126. 40a41,50
  127. > ;;; klm 20-Mar-1992 Parameterize the hanging-list prefixes so we can add to
  128. > ;;;            it from, eg, outline mode...
  129. > (defvar filladapt-hanging-list-prefixes
  130. >   '(" *(?\\([0-9]+[a-z]?\\|[a-z]\\)) +"
  131. >     " *\\([0-9]+[a-z]?\\|[a-z]\\)\\. +"
  132. >     " *[?!"~*+---]+ +")
  133. >   "A list of regular expression strings which can head hanging lists.")
  134. > ;;;klm My 'outext.el' adds a 'filladapt-hanging-list' entry for the fancy
  135. > ;;;    outline prefixes.
  136. 57,61c67,71
  137. <     ;; 1. xxxxx   or   *   xxxxx   etc.
  138. <     ;;    xxxxx            xxx
  139. <     (" *(?\\([0-9]+[a-z]?\\|[a-z]\\)) +" . filladapt-hanging-list)
  140. <     (" *\\([0-9]+[a-z]?\\|[a-z]\\)\\. +" . filladapt-hanging-list)
  141. <     ("[?!~*+--- ]+ " . filladapt-hanging-list)
  142. ---
  143. >     ;; 1. xxxxx      or   *   xxxxx   etc.
  144. >     ;;      xxxxx           xxx
  145. >     (" *(?\\([0-9:]+[a-z]?\\|[a-z]\\)) +" . filladapt-hanging-list)
  146. >     (" *\\([0-9:]+[a-z]?\\|[a-z]\\)\\. +" . filladapt-hanging-list)
  147. >     ("[?!~*+:--- ]+ " . filladapt-hanging-list)
  148. 72c82
  149. < is found the crorrespoding FUNCTION is called.  FUNCTION is called with
  150. ---
  151. > is found the corresponding FUNCTION is called.    FUNCTION is called with
  152. 157a168,173
  153. > (defun filladapt-looking-at-prefixes (prefixes)
  154. >   "Recursively check point for prefixes, until we find one."
  155. >   (cond ((null prefixes) nil)
  156. >     ((looking-at (car prefixes)))
  157. >     (t (filladapt-looking-at-prefixes (cdr prefixes)))))
  158. 165a182
  159. >         ;; Get to the beginning of the indented stuff:
  160. 168,173c185,192
  161. <         (cond ((or (looking-at " *(?\\([0-9]+[a-z]?\\|[a-z]\\)) +")
  162. <                (looking-at " *\\([0-9]+[a-z]?\\|[a-z]\\)\\. +")
  163. <                (looking-at " *[?!~*+---]+ +"))
  164. <                (setq beg (point)))
  165. <               (t (setq beg (progn (forward-line 1) (point))))))
  166. <         (setq beg (point)))
  167. ---
  168. >         ;; Check the line prior to the indented stuff for the prefix:
  169. >         (if (filladapt-looking-at-prefixes
  170. >              filladapt-hanging-list-prefixes)
  171. >             ;; setting the beginning to the match if we found it:
  172. >             (setq beg (match-end 0))
  173. >           ;; else beginning of starting line if not:
  174. >           (setq beg (progn (forward-line 1) (point)))))
  175. >         (setq beg (match-end 0)))
  176.  
  177.  
  178. 8<-------------------------- Cut Here -------------------------->8
  179. ;; LCD Archive Entry:
  180. ;; allout|Ken Manheimer|klm@cme.nist.gov|
  181. ;; A more thorough outline-mode|
  182. ;; 07-05-92|V 2.1|~/modes/allout.el.Z|
  183.  
  184. ;; A full-fledged outline mode, based on the original rudimentary
  185. ;; GNU emacs outline functionality.  This version supercedes the
  186. ;; original GNU outline.el and my outext.el (v 1.1, which is the only
  187. ;; one i officially released).  klm 6-Apr-1992
  188. ;;
  189. ;; Ken Manheimer             Nat'l Inst of Standards and Technology
  190. ;; klm@cme.nist.gov (301)975-3539    (Formerly Nat'l Bureau of Standards)
  191. ;;    Factory Automation Systems Division Unix Systems Support Manager
  192.  
  193. ;; Copyright (C) 1991 Free Software Foundation, Inc.
  194.  
  195. ;; This file is part of GNU Emacs.
  196.  
  197. ;; GNU Emacs is distributed in the hope that it will be useful,
  198. ;; but WITHOUT ANY WARRANTY.  No author or distributor
  199. ;; accepts responsibility to anyone for the consequences of using it
  200. ;; or for whether it serves any particular purpose or works at all,
  201. ;; unless he says so in writing.  Refer to the GNU Emacs General Public
  202. ;; License for full details.
  203.  
  204. ;; Everyone is granted permission to copy, modify and redistribute
  205. ;; GNU Emacs, but only under the conditions described in the
  206. ;; GNU Emacs General Public License.   A copy of this license is
  207. ;; supposed to have been given to you along with GNU Emacs so you
  208. ;; can know your rights and responsibilities.  It should be in a
  209. ;; file named COPYING.  Among other things, the copyright notice
  210. ;; and this notice must be preserved on all copies.
  211.  
  212. (provide 'outline)
  213.  
  214. ;=======================================================================
  215. ;                     Outline Variables
  216.  
  217. ;-----------------------------------------------------------------------
  218. ; Basic configuration vars:
  219.  
  220. (defconst outline-primary-bullet "*") ;; This var should probably not be
  221.                                       ;; changed - backwards compatability
  222.                                       ;; and convention depend on it.
  223.  
  224. (defvar outline-plain-bullets-string ""
  225.   "   The bullets normally used in outline topic prefixes.  See
  226.    'outline-distinctive-bullets-string' for the other kind of
  227.    bullets.
  228.  
  229.    You must run 'set-outline-regexp' in order for changes to the
  230.    value of this var to effect outline-mode operation.")
  231. (setq outline-plain-bullets-string (concat outline-primary-bullet
  232.                                            "+-.:,;=%"))
  233. (make-variable-buffer-local 'outline-plain-bullets-string)
  234.  
  235. (defvar outline-distinctive-bullets-string ""
  236.   "   The bullets used for distinguishing outline topics.  These
  237.    bullets are not offered among the regular rotation, and are not
  238.    changed when automatically rebulleting, as when shifting the
  239.    level of a topic.  See 'outline-plain-bullets-string' for the
  240.    other kind of bullets.
  241.  
  242.    You must run 'set-outline-regexp' in order for changes
  243.    to the value of this var to effect outline-mode operation.")
  244. (setq outline-distinctive-bullets-string "&!?(#\"X@$~")
  245. (make-variable-buffer-local 'outline-distinctive-bullets-string)
  246.  
  247. (defvar outline-numbered-bullet ()
  248.   "   Bullet signifying outline prefixes which are to be numbered.
  249.    Leave it nil if you don't want any numbering, or set it to a
  250.    string with the bullet you want to be used.")
  251. (setq outline-numbered-bullet "#")
  252. (make-variable-buffer-local 'outline-numbered-bullet)
  253.  
  254. ;-----------------------------------------------------------------------
  255. ;                  Topic Header Style Configuration
  256. ;
  257. ; The following vars affect the basic behavior of outline topic
  258. ; creation and manipulation.
  259.  
  260. (defvar outline-stylish-prefixes t
  261.   "*A true value for this var makes the topic-prefix creation and modification
  262.    functions vary the prefix bullet char according to level.  Otherwise, only
  263.    asterisks ('*') and distinctive bullets are used.
  264.  
  265.    This is how an outline can look with stylish prefixes:
  266.  
  267.    * Top level
  268.    .* A topic
  269.    . + One level 3 subtopic
  270.    .  . One level 4 subtopic
  271.    . + Another level 3 subtopic
  272.    .  . A level 4 subtopic
  273.    .  #2 A distinguished, numbered level 4 subtopic
  274.    .  ! A distinguished ('!') level 4 subtopic
  275.    .  #4 Another numbered level 4 subtopic
  276.    
  277.    This would be an outline with stylish prefixes inhibited:
  278.  
  279.    * Top level
  280.    .* A topic
  281.    .! A distinctive (but measly) subtopic
  282.    . * A sub-subtopic - no bullets from outline-plain-bullets-string but '*'
  283.  
  284.    Stylish and constant prefixes (as well as old-style prefixes) are
  285.    always respected by the topic maneuvering functions, regardless of
  286.    this variable setting.
  287.  
  288.    The setting of this var is not relevant when outline-old-style-prefixes
  289.    is t.")
  290. (make-variable-buffer-local 'outline-stylish-prefixes)
  291.  
  292. (defvar outline-old-style-prefixes nil
  293.   "*Setting this var causes the topic-prefix creation and modification
  294.    functions to make only asterix-padded prefixes, so they look exactly
  295.    like the old style prefixes.
  296.  
  297.    Both old and new style prefixes are always respected by the topic
  298.    maneuvering functions.")
  299. (make-variable-buffer-local 'outline-old-style-prefixes)
  300.  
  301. ;-----------------------------------------------------------------------
  302. ; Incidental configuration vars (incidental subsystems interaction with
  303. ; outline):
  304.  
  305.                    ;;; Currently only works with Dan LaLiberte's isearch-mode:
  306. (defvar outline-enwrap-isearch-mode t
  307.   "*  Set this var non-nil if you have Dan LaLiberte's 'isearch-mode'
  308.    stuff, and want isearches to reveal hidden stuff encountered in the
  309.    course of a search (and reconceal it if you go past).")
  310.  
  311. (defvar outline-use-hanging-indents t
  312.   "*  Set this var non-nil if you have Kyle E Jones' filladapt stuff,
  313.   and you want outline to fill topics as hanging indents to the
  314.   bullets.")
  315. (make-local-variable 'outline-use-hanging-indents)
  316.  
  317. (defvar outline-reindent-bodies t
  318.   "*  Set this var non-nil if you want topic depth adjustments to
  319.   reindent hanging bodies (ie, bodies lines indented to beginning of
  320.   heading text).  The performance hit is small.")
  321. (make-local-variable 'outline-reindent-bodies)
  322.  
  323. ;-----------------------------------------------------------------------
  324. ; Internal configuration variables
  325.  
  326. (defvar outline-mode-map nil "Keybindings for outline mode.")
  327.  
  328. (defvar outline-regexp ""
  329.   "*   Regular expression to match the beginning of a heading line.
  330.    Any line whose beginning matches this regexp is considered a
  331.    heading.  This var is set according to the user configuration vars
  332.    by set-outline-regexp.")
  333.  
  334. (defvar outline-bullets-string ""
  335.   "   A string dictating the valid set of outline topic bullets.  This
  336.    var should *not* be set by the user - it is set by 'set-outline-regexp',
  337.    and is composed from the elements of 'outline-plain-bullets-string'
  338.    and 'outline-distinctive-bullets-string'.")
  339.  
  340. (defvar outline-line-boundary-regexp ()
  341.   "   outline-regexp with outline-style beginning of line anchor (ie,
  342.    C-j, *or* C-m, for prefixes of hidden topics, *or* beginning of the
  343.    buffer).  This is properly set when outline-regexp is produced by
  344.    'set-outline-regexp', so that (match-beginning 2) and (match-end 2)
  345.    delimit the prefix.")
  346.  
  347. ;;; Recent-topic-search-state data:
  348.  
  349. ;;; All basic outline functions which directly do string matches to
  350. ;;; evaluate heading prefix location set the variables
  351. ;;; outline-recent-prefix-beginning and outline-recent-prefix-end when
  352. ;;; successful.  Functions starting with 'outline-recent-' all use
  353. ;;; this state, providing the means to avoid redundant searches for
  354. ;;; just established data.  This optimization can be significant but
  355. ;;; must be employed carefully.
  356.  
  357. (defvar outline-recent-prefix-beginning 0
  358.   "   Buffer point of the start of the last topic prefix encountered.")
  359. (make-variable-buffer-local 'outline-recent-prefix-beginning)
  360. (defvar outline-recent-prefix-end 0
  361.   "   Buffer point of the end of the last topic prefix encountered.")
  362. (make-variable-buffer-local 'outline-recent-prefix-end)
  363.  
  364. ;=======================================================================
  365. ;                         Outline Initializations
  366.  
  367. (if outline-mode-map
  368.     nil
  369.   (setq outline-mode-map (copy-keymap text-mode-map))
  370.   (define-key outline-mode-map "\C-c\C-n" 'outline-next-visible-heading)
  371.   (define-key outline-mode-map "\C-c\C-p" 'outline-previous-visible-heading)
  372.   (define-key outline-mode-map "\C-c\C-i" 'outline-show-current-children)
  373.   (define-key outline-mode-map "\C-c\C-s" 'outline-show-current-subtree)
  374.   (define-key outline-mode-map "\C-c\C-h" 'outline-hide-current-subtree)
  375.   (define-key outline-mode-map "\C-c\C-u" 'outline-up-current-level)
  376.   (define-key outline-mode-map "\C-c\C-f" 'outline-forward-current-level)
  377.   (define-key outline-mode-map "\C-c\C-b" 'outline-backward-current-level)
  378.   ;; klm extensions:
  379.   (define-key outline-mode-map "\C-cc" 'outline-copy-exposed)
  380.   (define-key outline-mode-map "\C-c\C-a" 'outline-show-current-branches)
  381.   (define-key outline-mode-map "\C-c\C-e" 'outline-show-current-entry)
  382.   (define-key outline-mode-map "\C-c " 'open-sibtopic)
  383.   (define-key outline-mode-map "\C-c." 'open-subtopic)
  384.   (define-key outline-mode-map "\C-c," 'open-supertopic)
  385.   (define-key outline-mode-map "\C-c'" 'outline-shift-in)
  386.   (define-key outline-mode-map "\C-c>" 'outline-shift-in)
  387.   (define-key outline-mode-map "\C-c<" 'outline-shift-out)
  388.   (define-key outline-mode-map "\C-c\C-m" 'outline-rebullet-topic)
  389.   (define-key outline-mode-map "\C-cb" 'outline-rebullet-current-heading)
  390.   (define-key outline-mode-map "\C-c#" 'outline-number-siblings)
  391.   (define-key outline-mode-map "\C-k" 'outline-kill-line)
  392.   (define-key outline-mode-map "\C-y" 'outline-yank)
  393.   (define-key outline-mode-map "\M-y" 'outline-yank-pop)
  394.   (define-key outline-mode-map "\C-c\C-k" 'outline-kill-topic))
  395.  
  396.  
  397. (defun outline-mode ()
  398.   "  Set major mode for editing outlines with selective display.
  399.  
  400.    Below the description of the bindings is explanation of the outline
  401.    mode terminology.
  402.  
  403. Exposure Commands              Movement Commands
  404. C-c C-h    outline-hide-current-subtree  C-c C-n outline-next-visible-heading
  405. C-c C-i    outline-show-current-children C-c C-p outline-previous-visible-heading
  406. C-c C-s    outline-show-current-subtree  C-c C-u outline-up-current-level
  407. C-c C-a    outline-show-current-branches C-c C-f outline-forward-current-level
  408. C-c C-e    outline-show-current-entry    C-c C-b outline-backward-current-level
  409.         outline-show-all - expose entire buffer
  410.     outline-hide-current-leaves
  411.  
  412. Topic Header Generation Commands
  413. C-c     open-sibtopic        Create a header for a sibling of current topic
  414. C-c .    open-subtopic        ... for an offspring of current topic
  415. C-c ,    open-supertopic        ... for a sibling of the current topic's parent
  416.  
  417. Level and Prefix Adjustment Commands
  418. C-c >    outline-shift-in    Shift current topic and all offspring deeper
  419. C-c <    outline-shift-out    ... less deep
  420. C-c C-m    outline-rebullet-topic    Reconcile bullets of topic and offspring
  421. C-c b    outline-rebullet-current-heading Prompt for alternate bullet for
  422.                      current topic (no CR necessary)
  423. C-c #    outline-number-siblings    Number bullets of topic and siblings - the
  424.                 offspring are not affect.  With repeat count,
  425.                 revoke numbering.
  426. C-k    outline-kill-line    Kill line, reconciling subsequent numbering
  427. C-y    outline-yank        Yank, reconciling numbering, and adjusting
  428.                 yanked topics to depth of heading if yanking
  429.                 into bare topic prefix.
  430. M-y    outline-yank-pop    
  431. C-c C-k    outline-kill-topic    Kill current topic, including offspring.
  432.  
  433. Misc commands
  434. C-cc    outline-copy-exposed    Copy outline sans all hidden stuff to
  435.                 another buffer whose name is derived
  436.                 from the current one - \"XXX exposed\"
  437.  
  438.                              Terminology
  439.  
  440. Topic: A basic cohesive component of an emacs outline, which can
  441.        be closed (made hidden), opened (revealed), generated,
  442.        traversed, and shifted as units, using outline-mode functions.
  443.        A topic is composed of a HEADER, a BODY, and SUBTOPICs (see below).
  444.  
  445. Exposure: Hidden (~closed~) topics are represented by ellipses ('...')
  446.           at the end of the visible SUPERTOPIC which contains them,
  447.           rather than by their actual text.  Hidden topics are still
  448.           susceptable to editing and regular movement functions, they
  449.           just are not displayed normally, effectively collapsed into
  450.           the ellipses which represent them.  Outline mode provides
  451.           the means to selectively expose topics based on their
  452.           NESTING.
  453.  
  454.           SUBTOPICS of a topic can be hidden and subsequently revealed
  455.           based on their DEPTH relative to the supertopic from which
  456.           the exposure is being done.
  457.  
  458.           The BODIES of a topic do not generally become visible except
  459.           during exposure of entire subtrees (see documentation for
  460.           '-current-subtreesubtree'), or when the entry is explicitly exposed
  461.           with the 'outline-show-entry' function, or (if you have a special
  462.           version of isearch installed) when encountered by
  463.           incremental searches.
  464.  
  465.           The CURRENT topic is the more recent visible one before or
  466.           including the text cursor.
  467.  
  468. Header: The initial portion of an outline topic.  It is composed of a
  469.         topic header PREFIX at the beginning of the line, followed by
  470.         text to the end of the EFFECTIVE LINE.
  471.  
  472. Body: Any subsequent lines of text following a topic header and preceeding
  473.       the next one.  This is also referred to as the entry for a topic.
  474.  
  475. Prefix: The text which distinguishes topic headers from normal text
  476.         lines.  There are two forms, both of which start at the beginning
  477.         of the topic header (EFFECTIVE) line.  The length of the prefix
  478.         represents the DEPTH of the topic.  The fundamental sort begins
  479.         either with solely an asterisk ('*') or else dot ('.')  followed
  480.         by zero or more spaces and then an outline BULLET.  The second
  481.         form is for backwards compatability with the original emacs
  482.         outline mode, and consists solely of asterisks.  Both sorts are
  483.         recognized by all outline commands.  The first sort is generated
  484.         by outline topic production commands if the emacs variable
  485.         outline-old-style-prefixes is nil, otherwise the second style is
  486.         used.
  487.  
  488. Bullet: An outline prefix bullet is one of the characters on either
  489.         of the outline bullet string vars, 'outline-plain-bullets-string'
  490.         and 'outline-distinctive-bullets-string'.  (See their
  491.         documentation for more details.)  The default choice of bullet
  492.         for any prefix depends on the DEPTH of the topic.
  493.  
  494. Depth and Nesting:
  495.        The length of a topic header prefix, from the initial
  496.        character to the bullet (inclusive), represents the depth of
  497.        the topic.  A topic is considered to contain the subsequent
  498.        topics of greater depth up to the next topic of the same
  499.        depth, and the contained topics are recursively considered to
  500.        be nested within all containing topics.  Contained topics are
  501.        called subtopics.  Immediate subtopics are called 'children'.
  502.        Containing topics are supertopicsimmediate supertopics are
  503.        'parents'.  Contained topics of the same depth are called
  504.        siblings.
  505.  
  506. Effective line: The regular ascii text in which form outlines are
  507.                 saved are manipulated in outline-mode to engage emacs'
  508.                 selective-display faculty.  The upshot is that the
  509.                 effective end of an outline line can be terminated by
  510.                 either a normal Unix newline char, \n, or the special
  511.                 outline-mode eol, ^M.  This only matters at the user
  512.                 level when you're doing searches which key on the end of
  513.                 line character."
  514.  
  515.   (interactive)
  516.   (kill-all-local-variables)
  517.   (setq selective-display t)
  518.   (use-local-map outline-mode-map)
  519.   (setq mode-name "Outline")
  520.   (setq major-mode 'outline-mode)
  521.   (define-abbrev-table 'text-mode-abbrev-table ())
  522.   (setq local-abbrev-table text-mode-abbrev-table)
  523.   (set-syntax-table text-mode-syntax-table)
  524.   ;; klm extension:
  525.   (set-outline-regexp)
  526.  
  527.   (make-local-variable 'paragraph-start)
  528.   (setq paragraph-start (concat paragraph-start "\\|^\\("
  529.                 outline-regexp "\\)"))
  530.   (make-local-variable 'paragraph-separate)
  531.   (setq paragraph-separate (concat paragraph-separate "\\|^\\("
  532.                    outline-regexp "\\)"))
  533.  
  534.   ;; klm extension:
  535.   (if outline-enwrap-isearch-mode
  536.       (outline-enwrap-isearch))
  537.   ;; klm extension:
  538.   (if (and outline-use-hanging-indents
  539.            (boundp 'filladapt-prefix-table))
  540.       ;; Add outline-prefix recognition to filladapt - not standard:
  541.       (progn (setq filladapt-prefix-table
  542.                    (cons (cons (concat "\\(" outline-regexp "\\) ")
  543.                                'filladapt-hanging-list)
  544.                          filladapt-prefix-table))
  545.              (setq filladapt-hanging-list-prefixes
  546.                    (cons outline-regexp filladapt-hanging-list-prefixes))))
  547.  
  548.  
  549.   (run-hooks 'text-mode-hook 'outline-mode-hook))
  550.  
  551. (defun set-outline-regexp ()
  552.   "   Generate proper topic-header regexp form for outline functions, from
  553.    outline-plain-bullets-string and outline-distinctive-bullets-string."
  554.  
  555.   (interactive)
  556.   ;; Derive outline-bullets-string from user configured components:
  557.   (setq outline-bullets-string (concat outline-plain-bullets-string
  558.                                        outline-distinctive-bullets-string))
  559.   ;; Derive next for repeated use in outline-pending-bullet:
  560.   (setq outline-plain-bullets-string-len (length outline-plain-bullets-string))
  561.   ;; Produce the new outline-regexp:
  562.   (set-outline-regexp-grunt (mapcar '(lambda (x) x) outline-bullets-string))
  563.   (setq outline-line-boundary-regexp
  564.         (concat "\\(\\`\\|[\C-j\C-m]\\)\\(" outline-regexp "\\)"))
  565.   (make-variable-buffer-local 'outline-regexp)
  566.   (make-variable-buffer-local 'outline-bullets-string)
  567.   (make-variable-buffer-local 'outline-line-boundary-regexp)
  568.   )
  569.  
  570. (defun set-outline-regexp-grunt (raw &optional cooked)
  571.   "   Do the real work for set-outline-regexp.  Requires a raw string of
  572.    bullets, RAW.  (Internally uses a second arg, COOKED, to recursively
  573.    accumulate the final form.)"
  574.   (cond
  575.  
  576.    ;; Base case, we've transformed all of 'raw' to 'cooked' - finish up:
  577.    ((null raw)
  578.     (setq outline-regexp (concat "\\(\\. *[" cooked "]\\)\\|\\*+\\|\^l")))
  579.  
  580.    ;; Initialization case - no vals - prime function:
  581.    ((null cooked) (set-outline-regexp-grunt raw ""))
  582.  
  583.    ;; Recurse with leading char in raw form transformed to proper escaped
  584.    ;; string on end of cooked form:
  585.    ((let* ((this-char (car raw))
  586.        (this-bullet (char-to-string this-char)))
  587.       ;; The recursive invocation:
  588.       (set-outline-regexp-grunt
  589.        ;; The remaining raw string:
  590.        (cdr raw)
  591.        ;; The burgeoning cooked string:
  592.        (concat cooked
  593.                ;; Do the right thing for various chars:
  594.                (cond ((eq this-char ?-) "--")
  595.                      ((eq this-char ?\() (char-to-string this-char))
  596.                      (t (concat  "\\" (char-to-string this-char)))))
  597.        )
  598.       ))
  599.    )
  600.   )
  601.  
  602. ;-----------------------------------------------------------------------
  603. ;                      Outline State Functions
  604.  
  605. (defun outline-recent-depth ()
  606.   "   Return depth of last heading encountered by an outline maneuvering
  607.    function.
  608.  
  609.    All outline functions which directly do string matches to assess
  610.    headings set the variables outline-recent-prefix-beginning and
  611.    outline-recent-prefix-end if successful.  This function uses those settings
  612.    to return the current depth."
  613.  
  614.   (- outline-recent-prefix-end outline-recent-prefix-beginning))
  615.  
  616. (defun outline-recent-prefix ()
  617.   "   Like outline-recent-depth, but returns text of last encountered prefix.
  618.  
  619.    All outline functions which directly do string matches to assess
  620.    headings set the variables outline-recent-prefix-beginning and
  621.    outline-recent-prefix-end if successful.  This function uses those settings
  622.    to return the current depth."
  623.   (buffer-substring outline-recent-prefix-beginning outline-recent-prefix-end))
  624.  
  625. (defun outline-recent-bullet ()
  626.   "   Like outline-recent-prefix, but returns bullet of last encountered
  627.    prefix.
  628.  
  629.    All outline functions which directly do string matches to assess
  630.    headings set the variables outline-recent-prefix-beginning and
  631.    outline-recent-prefix-end if successful.  This function uses those settings
  632.    to return the current depth of the most recently matched topic."
  633.   (buffer-substring (1- outline-recent-prefix-end) outline-recent-prefix-end))
  634.  
  635. ;--------------------------------------------------------------------
  636. ;                   Fundamental Location Assement
  637.  
  638. (defun outline-on-current-heading-p ()
  639.   "   Return prefix beginning point if point is on same line as current
  640.    visible topic's header line."
  641.   (save-excursion
  642.     (beginning-of-line)
  643.     (and (looking-at outline-regexp)
  644.          (setq outline-recent-prefix-end (match-end 0)
  645.                outline-recent-prefix-beginning (match-beginning 0)))))
  646.  
  647. (defun outline-hidden-p ()
  648.   "True if point is in hidden text."
  649.   (interactive)
  650.   (save-excursion
  651.     (and (re-search-backward "[\C-j\C-m]" (point-min) t)
  652.          (looking-at "\C-m"))))
  653.  
  654. (defun outline-current-depth ()
  655.   "   Return the depth to which the current containing visible topic is
  656.    nested in the outline."
  657.   (save-excursion
  658.     (if (outline-back-to-current-heading)
  659.         (- outline-recent-prefix-end
  660.            outline-recent-prefix-beginning)
  661.       0)))
  662.  
  663. (defun outline-depth ()
  664.   "   Like outline-current-depth, but respects hidden as well as visible
  665.    topics."
  666.   (save-excursion
  667.     (if (outline-goto-prefix)
  668.         (outline-recent-depth)
  669.       (progn
  670.         (setq outline-recent-prefix-end (point)
  671.               outline-recent-prefix-beginning (point))
  672.         0))))
  673.  
  674. ;--------------------------------------------------------------------
  675. ;                 Fundamental Topic Prefix Assement
  676.  
  677. (defun outline-get-current-prefix ()
  678.   "   Topic prefix of the current topic."
  679.   (save-excursion
  680.     (if (outline-goto-prefix)
  681.         (outline-recent-prefix))))
  682. (defun outline-get-bullet ()
  683.   "   Return bullet of current topic."
  684.   (save-excursion
  685.     (and (outline-goto-prefix)
  686.          (outline-recent-bullet))))
  687.  
  688. (defun outline-get-prefix-bullet (prefix)
  689.   "   Return the bullet of the header prefix string PREFIX."
  690.   ;; Doesn't make sense if we're old-style prefixes, but this just
  691.   ;; oughtn't be called then, so forget about it...
  692.   (if (string-match outline-regexp prefix)
  693.       (substring prefix (1- (match-end 0)) (match-end 0))))
  694.  
  695. ;-----------------------------------------------------------------------
  696. ;                         Fundamental Motion
  697.  
  698. (defun outline-back-to-current-heading ()
  699.   "   Move to heading line of current visible topic, or beginning of heading
  700.    if already on visible heading line."
  701.   (beginning-of-line)
  702.   (or (outline-on-current-heading-p)
  703.       (and (re-search-backward (concat "^\\(" outline-regexp "\\)") nil 'move)
  704.            (setq outline-recent-prefix-end (match-end 1)
  705.                  outline-recent-prefix-beginning (match-beginning 1)))))
  706.  
  707. (defun outline-goto-prefix ()
  708.   "  Put point at beginning of outline prefix for current topic, visible
  709.    or not.
  710.  
  711.    Returns a list of char address of the beginning of the prefix and the
  712.    end of it, or nil if none."
  713.  
  714.   (cond ((and (or (bobp)
  715.                   (memq (preceding-char) '(?\n ?\^M)))
  716.               (looking-at outline-regexp))
  717.          (setq outline-recent-prefix-end (match-end 0)
  718.                outline-recent-prefix-beginning
  719.                (goto-char (match-beginning 0))))
  720.         ((re-search-backward outline-line-boundary-regexp
  721.                              ;; unbounded search,
  722.                              ;; stay at limit and return nil if failed:
  723.                              nil 1)
  724.          (setq outline-recent-prefix-end (match-end 2)
  725.                outline-recent-prefix-beginning
  726.                (goto-char (match-beginning 2)))))
  727.  )
  728.  
  729. (defun outline-next-preface ()
  730.   "Skip forward to just before the next heading line.
  731.  
  732.    Returns that character position."
  733.  
  734.   (if (re-search-forward outline-line-boundary-regexp nil 'move)
  735.       (progn (goto-char (match-beginning 0))
  736.              (setq outline-recent-prefix-end (match-end 2)
  737.                    outline-recent-prefix-beginning (match-beginning 2)))))
  738.  
  739.  
  740. (defun outline-ascend-to-depth (depth)
  741.   "   Ascend to depth DEPTH, returning depth if successful, nil if not."
  742.   (if (and (> depth 0)(<= depth (outline-depth)))
  743.       (let ((last-good (point)))
  744.         (while (and (< depth (outline-depth))
  745.                     (setq last-good (point))
  746.                     (outline-beginning-of-level)
  747.                     (outline-previous-heading)))
  748.         (if (= (outline-recent-depth) depth)
  749.             (progn (goto-char outline-recent-prefix-beginning)
  750.                    depth)
  751.           (goto-char last-good)
  752.           nil))))
  753.  
  754. (defun outline-descend-to-depth (depth)
  755.   "   Descend to depth DEPTH within current topic, returning depth if
  756.    successful, nil if not."
  757.   (let ((start-point (point))
  758.         (start-depth (outline-depth)))
  759.     (while (and (> (outline-depth) 0)
  760.                 (not (= depth (outline-recent-depth)))     ; ... not there yet
  761.                 (outline-next-heading)            ; ... go further
  762.                 (< start-depth (outline-recent-depth)))) ; ... still in topic
  763.     (if (and (> (outline-depth) 0)
  764.              (= (outline-recent-depth) depth))
  765.         depth
  766.       (goto-char start-point)
  767.       nil))
  768.   )
  769.  
  770. (defun outline-end-of-current-subtree ()
  771.   (outline-back-to-current-heading)
  772.   (let ((opoint (point))
  773.     (level (outline-recent-depth)))
  774.     (outline-next-heading)
  775.     (while (and (not (eobp))
  776.                 (> (outline-recent-depth) level))
  777.       (outline-next-heading))
  778.     (if (not (eobp)) (forward-char -1))
  779.     (if (memq (preceding-char) '(?\n ?\^M)) (forward-char -1))))
  780.  
  781. (defun outline-next-visible-heading (arg)
  782.   "   Move to the next visible heading line.
  783.  
  784.    With argument, repeats or can move backward if negative.
  785.    A heading line is one that starts with a `*' (or that outline-regexp
  786.    matches)."
  787.   (interactive "p")
  788.   (if (< arg 0) (beginning-of-line) (end-of-line))
  789.   (if (re-search-forward (concat "^\\(" outline-regexp "\\)") nil 'go arg)
  790.       (progn (beginning-of-line)
  791.              (setq outline-recent-prefix-end (match-end 1)
  792.                    outline-recent-prefix-beginning (match-beginning 1)))))
  793.  
  794. (defun outline-previous-visible-heading (arg)
  795.   "   Move to the previous heading line.
  796.  
  797.    With argument, repeats or can move forward if negative.
  798.    A heading line is one that starts with a `*' (or that outline-regexp
  799.    matches)."
  800.   (interactive "p")
  801.   (outline-next-visible-heading (- arg)))
  802.  
  803. (defun outline-next-heading (&optional backward)
  804.   "   Move to the heading for the topic (possibly invisible) before this one.
  805.  
  806.    Optional arg BACKWARD means search for most recent prior heading.
  807.  
  808.    Returns the location of the heading, or nil if none found."
  809.  
  810.   (if backward (outline-goto-prefix)
  811.     (if (bobp) (forward-char 1)))
  812.  
  813.   (if (if backward
  814.           ;; searches are unbounded and return nil if failed:
  815.           (re-search-backward outline-line-boundary-regexp
  816.                               nil
  817.                               0)
  818.         (re-search-forward outline-line-boundary-regexp
  819.                            nil
  820.                            0))
  821.       (progn;; Got some valid location state - set vars:
  822.         (setq outline-recent-prefix-end (match-end 2))
  823.         (goto-char (setq outline-recent-prefix-beginning
  824.                          (match-beginning 2))))
  825.     )
  826.   )
  827. (defun outline-previous-heading ()
  828.   "   Move to the next (possibly invisible) heading line.
  829.  
  830.    Optional repeat-count arg means go that number of headings.
  831.  
  832.    Return the location of the beginning of the heading, or nil if not found."
  833.  
  834.   (outline-next-heading t))
  835.  
  836. (defun outline-next-sibling (&optional backward)
  837.   "   Like outline-forward-current-level, but respects invisible topics.
  838.  
  839.    Go backward if optional arg BACKWARD is non-nil.
  840.  
  841.    Return depth if successful, nil otherwise."
  842.  
  843.   (if (and backward (bobp))
  844.       nil
  845.     (let ((start-depth (outline-depth))
  846.           (start-point (point))
  847.           last-good)
  848.       (while (and (not (if backward (bobp) (eobp)))
  849.                   (if backward (outline-previous-heading)
  850.                     (outline-next-heading))
  851.                   (> (outline-recent-depth) start-depth)))
  852.       (if (and (not (eobp))
  853.                (and (> (outline-depth) 0)
  854.                     (= (outline-recent-depth) start-depth)))
  855.           outline-recent-prefix-beginning
  856.         (goto-char start-point)
  857.         nil)
  858.       )
  859.     )
  860.   )
  861. (defun outline-previous-sibling (&optional arg)
  862.   "   Like outline-forward-current-level, but goes backwards and respects
  863.    invisible topics.
  864.  
  865.    Optional repeat count means go number backward.
  866.  
  867.    Note that the beginning of a level is (currently) defined by this
  868.    implementation to be the first of previous successor topics of
  869.    equal or greater depth.
  870.  
  871.    Return depth if successful, nil otherwise."
  872.   (outline-next-sibling t))
  873.  
  874. (defun outline-beginning-of-level ()
  875.   "   Go back to the first sibling at this level, visible or not."
  876.   (outline-end-of-level 'backward))
  877. ;klm transferred
  878. (defun outline-end-of-level (&optional backward)
  879.   "   Go to the last sibling at this level, visible or not."
  880.  
  881.   (while (outline-previous-sibling))
  882.   (outline-recent-depth))
  883.  
  884. (defun outline-up-current-level (arg)
  885.   "   Move to the heading line of which the present line is a subheading.
  886.    With argument, move up ARG levels."
  887.   (interactive "p")
  888.   (outline-back-to-current-heading)
  889.   (let ((present-level (outline-recent-depth)))
  890.     ;; Loop for iterating arg:
  891.     (while (and (> (outline-recent-depth) 1)
  892.                 (> arg 0)
  893.                 (not (bobp)))
  894.       ;; Loop for going back over current or greater depth:
  895.       (while (not (< (outline-recent-depth) present-level))
  896.         (outline-previous-visible-heading 1))
  897.       (setq present-level (outline-recent-depth))
  898.       (setq arg (- arg 1)))
  899.     )
  900.   (if (> arg 0)
  901.       (error "Can't ascend past level 1.")
  902.     outline-recent-prefix-beginning)
  903.   )
  904.  
  905. (defun outline-forward-current-level (arg &optional backward)
  906.   "   Position the point at the next heading of the same level, taking
  907.    optional repeat-count.
  908.  
  909.    Returns that position, else nil if is not found."
  910.   (interactive "p")
  911.   (outline-back-to-current-heading)
  912.   (let ((amt (if arg (if (< arg 0)
  913.                          ;; Negative arg - invert direction.
  914.                          (progn (setq backward (not backward))
  915.                                 (abs arg))
  916.                        arg)          ;; Positive arg - just use it.
  917.                1)))              ;; No arg - use 1:
  918.     (while (and (> amt 0)
  919.                 (outline-next-sibling backward))
  920.       (setq amt (1- amt)))
  921.     (if (> amt 0)
  922.         (if (and arg (= (abs arg) amt))
  923.           (error "This is the %s topic on this level."
  924.                  (if backward "first" "last"))
  925.           (error "There are no more topics on this level %s this"
  926.                  (if backward "before" "after")))
  927.       t)
  928.     )
  929.   )
  930. (defun outline-backward-current-level (arg)
  931.   "   Position the point at the previous heading of the same level, taking
  932.    optional repeat-count.
  933.  
  934.    Returns that position, else nil if is not found."
  935.   (interactive "p")
  936.   (outline-forward-current-level arg t))
  937.  
  938. (defun outline-next-visible-sibling ()
  939.   "   Position the point at the next heading of the same level, 
  940.    and return that position, else nil if is not found."
  941.   (let ((level (outline-current-depth)))
  942.     (if (outline-next-visible-heading 1)
  943.         (progn (while (and (> (outline-recent-depth) level) (not (eobp)))
  944.                  (outline-next-visible-heading 1))
  945.                (if (< (outline-recent-depth) level) nil (point))))))
  946. (defun outline-previous-visible-sibling ()
  947.   "   Position the point at the previous heading of the same level, 
  948.    and return that position or nil if it cannot be found."
  949.   (let ((level (outline-current-depth)))
  950.     (if (outline-previous-visible-heading 1)
  951.         (progn (while (and (> (outline-recent-depth) level) (not (bobp)))
  952.                  (outline-previous-visible-heading 1))
  953.                (if (< (outline-recent-depth) level) nil (point))))))
  954.  
  955. ;-----------------------------------------------------------------------
  956. ;            Fundamental Outline Exposure Control Function
  957.  
  958. (defun outline-flag-region (from to flag)
  959.   "   Hides or shows lines from FROM to TO, according to FLAG.
  960.    Uses emacs selective-display, where text is show if FLAG put at
  961.    beginning of line is `\\n' (newline character), while text is
  962.    hidden if FLAG is `\\^M' (control-M)."
  963.   (let ((modp (buffer-modified-p)))
  964.     (unwind-protect
  965.         (subst-char-in-region from to
  966.                   (if (= flag ?\n) ?\^M ?\n)
  967.                   flag t)
  968.      (set-buffer-modified-p modp))))
  969.  
  970. ;-----------------------------------------------------------------------
  971. ;                  Topic Component Exposure Control
  972.  
  973. (defun outline-hide-current-entry ()
  974.   "Hide the body directly following this heading."
  975.   (interactive)
  976.   (outline-back-to-current-heading)
  977.   (save-excursion
  978.    (outline-flag-region (point) (progn (outline-next-preface) (point)) ?\^M)))
  979.  
  980. (defun outline-show-current-entry ()
  981.   "Show the body directly following this heading."
  982.   (interactive)
  983.   (save-excursion
  984.    (outline-flag-region (point) (progn (outline-next-preface) (point)) ?\n)))
  985.  
  986. ; outline-show-entry basically for isearch dynamic exposure, as is...
  987. (defun outline-show-entry ()
  988.   "   Like outline-show-current-entry, but reveals an entry that is nested
  989.    within hidden topics."
  990.   (interactive)
  991.   (save-excursion
  992.     (outline-goto-prefix)
  993.     (outline-flag-region (if (not (bobp)) (1- (point)) (point))
  994.                          (progn (outline-next-preface) (point)) ?\n)))
  995.  
  996. ; ... outline-hide-current-entry-completely also for isearch dynamic exposure:
  997. (defun outline-hide-current-entry-completely ()
  998.   "Like outline-hide-current-entry, but conceal topic completely."
  999.   (interactive)
  1000.   (save-excursion
  1001.     (outline-goto-prefix)
  1002.     (outline-flag-region (if (not (bobp)) (1- (point)) (point))
  1003.                          (progn (outline-next-preface) (point)) ?\C-m)))
  1004.  
  1005. (defun outline-hide-bodies ()
  1006.   "Hide all of buffer except headings."
  1007.   (interactive)
  1008.   (outline-hide-region-body (point-min) (point-max)))
  1009.  
  1010. ;-----------------------------------------------------------------------
  1011. ;                 Composite Topics Exposure Control
  1012.  
  1013. (defun outline-hide-region-body (start end)
  1014.   "Hide all body lines in the region, but not headings."
  1015.   (save-excursion
  1016.     (save-restriction
  1017.       (narrow-to-region start end)
  1018.       (goto-char (point-min))
  1019.       (while (not (eobp))
  1020.     (outline-flag-region (point)
  1021.                              (progn (outline-next-preface) (point)) ?\^M)
  1022.     (if (not (eobp))
  1023.         (forward-char
  1024.          (if (looking-at "[\n\^M][\n\^M]")
  1025.          2 1)))))))
  1026.  
  1027. (defun outline-show-all ()
  1028.   "Show all of the text in the buffer."
  1029.   (interactive)
  1030.   (outline-flag-region (point-min) (point-max) ?\n))
  1031.  
  1032. (defun outline-show-current-branches ()
  1033.   "Show all subheadings of this heading, but not their bodies."
  1034.   (interactive)
  1035.   (outline-show-current-children 1000))
  1036.  
  1037. (defun outline-flag-current-subtree (flag)
  1038.   (save-excursion
  1039.     (outline-back-to-current-heading)
  1040.     (outline-flag-region (point)
  1041.               (progn (outline-end-of-current-subtree) (point))
  1042.               flag)))
  1043.  
  1044. (defun outline-hide-current-subtree ()
  1045.   "Hide everything after this heading at deeper levels."
  1046.   (interactive)
  1047.   (outline-flag-current-subtree ?\^M))
  1048.  
  1049. (defun outline-hide-current-leaves ()
  1050.   "Hide all body after this heading at deeper levels."
  1051.   (interactive)
  1052.   (outline-back-to-current-heading)
  1053.   (outline-hide-region-body (point) (progn (outline-end-of-current-subtree)
  1054.                                            (point))))
  1055.  
  1056. (defun outline-show-current-subtree ()
  1057.   "Show everything after this heading at deeper levels."
  1058.   (interactive)
  1059.   (outline-flag-current-subtree ?\n))
  1060.  
  1061. (defun outline-show-current-children (&optional level)
  1062.   "  Show all direct subheadings of this heading.  Optional LEVEL specifies
  1063.    how many levels below the current level should be shown."
  1064.   (interactive "p")
  1065.   (or level (setq level 1))
  1066.   (save-excursion
  1067.    (save-restriction
  1068.     (beginning-of-line)
  1069.     (setq level (+ level (progn (outline-back-to-current-heading)
  1070.                                 (outline-recent-depth))))
  1071.     (narrow-to-region (point)
  1072.               (progn (outline-end-of-current-subtree) (1+ (point))))
  1073.     (goto-char (point-min))
  1074.     (while (and (not (eobp))
  1075.                 (outline-next-heading))
  1076.       (if (<= (outline-recent-depth) level)
  1077.       (save-excursion
  1078.        (let ((end (1+ (point))))
  1079.          (forward-char -1)
  1080.          (if (memq (preceding-char) '(?\n ?\^M))
  1081.          (forward-char -1))
  1082.          (outline-flag-region (point) end ?\n))))))))
  1083.  
  1084. ;-------------------------------------------------------------------
  1085. ; Something added solely for use by a "smart menu" package someone got
  1086. ; off the net.  I have no idea whether this is appropriate code.
  1087.  
  1088. (defun outline-to-entry-end (&optional include-sub-entries curr-entry-level)
  1089.   "   Go to end of whole entry if optional INCLUDE-SUB-ENTRIES is non-nil.
  1090.    CURR-ENTRY-LEVEL is an integer representing the length of the current level
  1091.    string which matched to 'outline-regexp'.  If INCLUDE-SUB-ENTRIES is nil,
  1092.    CURR-ENTRY-LEVEL is not needed."
  1093.   (while (and (setq next-entry-exists
  1094.             (re-search-forward outline-regexp nil t))
  1095.           include-sub-entries
  1096.           (save-excursion
  1097.         (beginning-of-line)
  1098.         (> (outline-depth) curr-entry-level))))
  1099.   (if next-entry-exists
  1100.       (progn (beginning-of-line) (point))
  1101.     (goto-char (point-max))))
  1102.  
  1103. ;;;-------------------------------------------------------------------------
  1104. ;;; Outline topic prefix and level adjustment funcs:
  1105.  
  1106. (defun outline-bullet-for-depth (&optional depth)
  1107.   "   Return outline topic bullet suited to DEPTH, or for current depth if none
  1108.    specified."
  1109.   ;; Find bullet in plain-bullets-string modulo DEPTH.
  1110.   (if (null depth) (setq depth (outline-visible-depth)))
  1111.   (if outline-stylish-prefixes
  1112.       (char-to-string (aref outline-plain-bullets-string
  1113.                             (% (max 0 (- depth 2))
  1114.                                outline-plain-bullets-string-len)))
  1115.     outline-primary-bullet)
  1116.   )
  1117.  
  1118.  
  1119. (defun outline-sibling-index (&optional depth)
  1120.   "   Item number of this prospective topic among it's siblings.
  1121.  
  1122.    If optional arg depth is greater than current depth, then we're
  1123.    opening a new level, and return 0.
  1124.  
  1125.    If less than this depth, ascend to that depth and count..."
  1126.  
  1127.   (save-excursion
  1128.     (cond ((and depth (<= depth 0) 0))
  1129.           ((or (not depth) (= depth (outline-depth)))
  1130.            (let ((index 1))
  1131.              (while (outline-previous-sibling) (setq index (1+ index)))
  1132.              index))
  1133.           ((< depth (outline-recent-depth))
  1134.            (outline-ascend-to-depth depth)
  1135.            (outline-sibling-index))
  1136.           (0))))
  1137.  
  1138. (defun solicit-char-in-string (prompt string &optional do-defaulting)
  1139.   "   Solicit (with first arg PROMPT) choice of a character from string STRING.
  1140.  
  1141.    Optional arg DO-DEFAULTING indicates to accept empty input (CR)."
  1142.  
  1143.   (let ((new-prompt prompt)
  1144.         got)
  1145.  
  1146.     (while (not got)
  1147.       (message "%s" new-prompt)
  1148.  
  1149.       ;; We do our own reading here, so we can circumvent, eg, special
  1150.       ;; treatment for '?' character.  (Might oughta change minibuffer
  1151.       ;; keymap instead, oh well.)
  1152.       (setq got
  1153.             (char-to-string (let ((cursor-in-echo-area t)) (read-char))))
  1154.  
  1155.       (if (null (string-match got string))
  1156.           (if (and do-defaulting (string= got "\^M"))
  1157.               ;; We're defaulting, return null string to indicate that:
  1158.               (setq got "")
  1159.             ;; Failed match and not defaulting,
  1160.             ;; set the prompt to give feedback,
  1161.             (setq new-prompt (concat prompt
  1162.                                      got
  1163.                                      " ...pick from: "
  1164.                                      string
  1165.                                      ""))
  1166.             ;; and set loop to try again:
  1167.             (setq got nil))
  1168.         ;; Got a match - give feedback:
  1169.         (message "")))
  1170.     ;; got something out of loop - return it:
  1171.     got)
  1172.   )
  1173.  
  1174. (defun outline-solicit-alternate-bullet (depth &optional current-bullet)
  1175.  
  1176.   "   Prompt for and return a bullet char as an alternative to the
  1177.    current one, but offer one suitable for current depth DEPTH
  1178.    as default."
  1179.  
  1180.   (let* ((default-bullet (or current-bullet
  1181.                              (outline-bullet-for-depth depth)))
  1182.      (choice (solicit-char-in-string
  1183.                   (format "Choose a bullet from '%s' [%s]: "
  1184.                           outline-bullets-string
  1185.                           default-bullet)
  1186.                   outline-bullets-string
  1187.                   t)))
  1188.     (if (string= choice "") default-bullet choice))
  1189.   )
  1190.  
  1191. (defun outline-distinctive-bullet (bullet)
  1192.   "   True if bullet is one of those on outline-distinctive-bullets-string."
  1193.   (string-match (regexp-quote bullet) outline-distinctive-bullets-string))
  1194.  
  1195. (defun outline-numbered-type-prefix (&optional prefix)
  1196.   "   True if current header prefix bullet is numbered bullet."
  1197.   (and outline-numbered-bullet
  1198.         (string= outline-numbered-bullet
  1199.                  (if prefix
  1200.                      (outline-get-prefix-bullet prefix)
  1201.                    (outline-get-bullet)))))
  1202.  
  1203. (defun outline-make-topic-prefix (&optional prior-bullet
  1204.                                             new
  1205.                                             depth
  1206.                                             solicit
  1207.                                             number-control
  1208.                                             index)
  1209.   ;; Depth null means use current depth, non-null means we're either
  1210.   ;; opening a new topic after current topic, lower or higher, or we're
  1211.   ;; changing level of current topic.
  1212.   ;; Solicit dominates specified bullet-char.
  1213.   "   Generate a topic prefix suitable for optional arg DEPTH, or current
  1214.    depth if not specified.
  1215.  
  1216.    All the arguments are optional.
  1217.  
  1218.    PRIOR-BULLET indicates the bullet of the prefix being changed, or
  1219.    nil if none.  This bullet may be preserved (other options
  1220.    notwithstanding) if it is on the outline-distinctive-bullets-string,
  1221.    for instance.
  1222.  
  1223.    Second arg NEW indicates that a new topic is being opened after the
  1224.    topic at point, if non-nil.  Default bullet for new topics, eg, may
  1225.    be set (contingent to other args) to numbered bullets if previous
  1226.    sibling is one.  The implication otherwise is that the current topic
  1227.    is being adjusted - shifted or rebulleted - and we don't consider
  1228.    bullet or previous sibling.
  1229.  
  1230.    Third arg DEPTH forces the topic prefix to that depth, regardless of
  1231.    the current topics' depth.
  1232.  
  1233.    Fourth arg SOLICIT non-nil provokes solicitation from the user of a
  1234.    choice among the valid bullets.  (This overrides other all the
  1235.    options, including, eg, a distinctive PRIOR-BULLET.)
  1236.  
  1237.    Fifth arg, NUMBER-CONTROL, matters only if 'outline-numbered-bullet'
  1238.    is non-nil *and* soliciting was not explicitly invoked.  Then
  1239.    NUMBER-CONTROL non-nil forces prefix to either numbered or
  1240.    denumbered format, depending on the value of the sixth arg, INDEX.
  1241.  
  1242.    (Note that NUMBER-CONTROL does *not* apply to level 1 topics.  Sorry...)
  1243.  
  1244.    If NUMBER-CONTROL is non-nil and sixth arg INDEX is non-nil then
  1245.    the prefix of the topic is forced to be numbered.  Non-nil
  1246.    NUMBER-CONTROL and nil INDEX forces non-numbered format on the
  1247.    bullet.  Non-nil NUMBER-CONTROL and non-nil, non-number INDEX means
  1248.    that the index for the numbered prefix will be derived, by counting
  1249.    siblings back to start of level.  If INDEX is a number, then that
  1250.    number is used as the index for the numbered prefix (allowing, eg,
  1251.    sequential renumbering to not requre this function counting back the
  1252.    index for each successive sibling)."
  1253.  
  1254.   ;; The options are ordered in likely frequence of use, most common
  1255.   ;; highest, least lowest.  Ie, more likely to be doing prefix
  1256.   ;; adjustments than soliciting, and yet more than numbering.
  1257.   ;; Current prefix is least dominant, but most likely to be commonly
  1258.   ;; specified...
  1259.  
  1260.   (let* (body
  1261.          numbering
  1262.          denumbering
  1263.          (depth (or depth (outline-depth)))
  1264.          (lead-char ".")
  1265.          (bullet-char
  1266.  
  1267.           ;; Getting value for bullet char is practically the whole job:
  1268.  
  1269.           (cond
  1270.                                         ; Simplest situation - level 1:
  1271.            ((<= depth 1) (setq lead-char "") outline-primary-bullet)
  1272.                                         ; Simple, too: all asterisks:
  1273.            (outline-old-style-prefixes
  1274.             ;; Cheat - make body the whole thing, null out lead-char and
  1275.             ;; bullet-char:
  1276.             (setq body (make-string depth
  1277.                                     (string-to-char outline-primary-bullet)))
  1278.             (setq lead-char "")
  1279.             "")
  1280.  
  1281.            ;; (Neither level 1 nor old-style, so we're space padding.
  1282.            ;; Sneak it in the condition of the next case, whatever it is.)
  1283.  
  1284.            ;; Solicitation overrides numbering and other cases:
  1285.            ((progn (setq body (make-string (- depth 2) ?\ ))
  1286.                    ;; The actual condition:
  1287.                    solicit)
  1288.             (let* ((got (outline-solicit-alternate-bullet depth)))
  1289.               ;; Gotta check whether we're numbering and got a numbered bullet:
  1290.               (setq numbering (and outline-numbered-bullet
  1291.                                    (not (and number-control (not index)))
  1292.                                    (string= got outline-numbered-bullet)))
  1293.               ;; Now return what we got, regardless:
  1294.               got))
  1295.  
  1296.            ;; Numbering invoked through args:
  1297.            ((and outline-numbered-bullet number-control)
  1298.             (if (setq numbering (not (setq denumbering (not index))))
  1299.                 outline-numbered-bullet
  1300.               (if (and current-bullet
  1301.                        (not (string= outline-numbered-bullet
  1302.                                      current-bullet)))
  1303.                   current-bullet
  1304.                 (outline-bullet-for-depth depth))))
  1305.  
  1306.           ;;; Neither soliciting nor controlled numbering ;;;
  1307.              ;;; (may be controlled denumbering, tho) ;;;
  1308.  
  1309.            ;; Check wrt previous sibling:
  1310.            ((and new                  ; only check for new prefixes
  1311.                  (<= depth (outline-depth))
  1312.                  outline-numbered-bullet          ; ... & numbering enabled
  1313.                  (not denumbering)
  1314.                  (let ((sibling-bullet
  1315.                         (save-excursion
  1316.                           ;; Locate correct sibling:
  1317.                           (or (>= depth (outline-depth))
  1318.                               (outline-ascend-to-depth depth))
  1319.                           (outline-get-bullet))))
  1320.                    (if (and sibling-bullet
  1321.                             (string= outline-numbered-bullet sibling-bullet))
  1322.                        (setq numbering sibling-bullet)))))
  1323.  
  1324.            ;; Distinctive prior bullet?
  1325.            ((and prior-bullet
  1326.                  (outline-distinctive-bullet prior-bullet)
  1327.                  ;; Either non-numbered:
  1328.                  (or (not (and outline-numbered-bullet
  1329.                                (string= prior-bullet outline-numbered-bullet)))
  1330.                      ;; or numbered, and not denumbering:
  1331.                      (setq numbering (not denumbering)))
  1332.                  ;; Here 'tis:
  1333.                  prior-bullet))
  1334.  
  1335.            ;; Else, standard bullet per depth:
  1336.            ((outline-bullet-for-depth depth)))))
  1337.  
  1338.     (concat lead-char
  1339.             body
  1340.             bullet-char
  1341.             (if numbering
  1342.                 (format "%d" (cond ((and index (numberp index)) index)
  1343.                                    (new (1+ (outline-sibling-index depth)))
  1344.                                    ((outline-sibling-index))))))
  1345.     )
  1346.   )
  1347.  
  1348. (defun outline-reindent-body (old-depth new-depth)
  1349.   "  Reindent body lines which were indented at old-depth to new-depth.
  1350.  
  1351.   Note that refill of indented paragraphs is not done, and tabs are
  1352.   not accomodated.  ('untabify' your outline if you want to preserve
  1353.   hanging body indents.)"
  1354.  
  1355.   (save-excursion
  1356.     (save-restriction
  1357.       (outline-goto-prefix)
  1358.       (forward-char 1)
  1359.       (let* ((old-spaces-expr (make-string (1+ old-depth) ?\ ))
  1360.              (new-spaces-expr (concat (make-string (1+ new-depth) ?\ )
  1361.                                       ;; spaces followed by non-space:
  1362.                                       "\\1")))
  1363.         (while (and (re-search-forward "[\C-j\C-m]" nil t)
  1364.                     (not (looking-at outline-regexp)))
  1365.           (if (looking-at old-spaces-expr)
  1366.               (replace-match new-spaces-expr)))))))
  1367.  
  1368. (defun outline-rebullet-current-heading (arg)
  1369.   "   Like non-interactive version 'outline-rebullet-heading', but work on
  1370.    (only) visible heading containing point.
  1371.  
  1372.    With repeat count, solicit for bullet."
  1373.   (interactive "P")
  1374.   (save-excursion (outline-back-to-current-heading)
  1375.                   (outline-rebullet-heading (not arg)    ;;; solicit
  1376.                                             nil        ;;; depth
  1377.                                             nil        ;;; number-control
  1378.                                             nil        ;;; index
  1379.                                             t)        ;;; do-successors
  1380.                   )
  1381.   )
  1382. (defun outline-rebullet-heading (&optional solicit
  1383.                                            new-depth
  1384.                                            number-control
  1385.                                            index
  1386.                                            do-successors)
  1387.  
  1388.   "   Adjust bullet of current topic prefix.
  1389.  
  1390.    All args are optional.
  1391.  
  1392.    If SOLICIT is non-nil then the choice of bullet is solicited from
  1393.    user.  Otherwise the distinctiveness of the bullet or the topic
  1394.    depth determines it.
  1395.  
  1396.    Second arg DEPTH forces the topic prefix to that depth, regardless
  1397.    of the topic's current depth.
  1398.  
  1399.    Third arg NUMBER-CONTROL can force the prefix to or away from
  1400.    numbered form.  It has effect only if 'outline-numbered-bullet' is
  1401.    non-nil and soliciting was not explicitly invoked (via first arg).
  1402.    Its effect, numbering or denumbering, then depends on the setting
  1403.    of the forth arg, INDEX.
  1404.  
  1405.    If NUMBER-CONTROL is non-nil and forth arg INDEX is nil, then the
  1406.    prefix of the topic is forced to be non-numbered.  Null index and
  1407.    non-nil NUMBER-CONTROL forces denumbering.  Non-nil INDEX (and
  1408.    non-nil NUMBER-CONTROL) forces a numbered-prefix form.  If non-nil
  1409.    INDEX is a number, then that number is used for the numbered
  1410.    prefix.  Non-nil and non-number means that the index for the
  1411.    numbered prefix will be derived by outline-make-topic-prefix.
  1412.  
  1413.    Fifth arg DO-SUCCESSORS t means re-resolve count on succeeding
  1414.    siblings.
  1415.  
  1416.    Cf vars 'outline-stylish-prefixes', 'outline-old-style-prefixes',
  1417.    and 'outline-numbered-bullet', which all affect the behavior of
  1418.    this function."
  1419.  
  1420.   (let* ((current-depth (outline-depth))
  1421.          (new-depth (or new-depth current-depth))
  1422.          (mb outline-recent-prefix-beginning)
  1423.          (me outline-recent-prefix-end)
  1424.          (current-bullet (buffer-substring (- me 1) me))
  1425.          (new-prefix (outline-make-topic-prefix current-bullet
  1426.                                                 nil
  1427.                                                 new-depth
  1428.                                                 solicit
  1429.                                                 number-control
  1430.                                                 index)))
  1431.  
  1432.     ;; Don't need to reinsert identical one:
  1433.     (if (and (= current-depth new-depth)
  1434.              (string= current-bullet
  1435.                       (substring new-prefix (1- (length new-prefix)))))
  1436.         t
  1437.  
  1438.       ;; New prefix probably different from old:
  1439.       ;; get rid of old one:
  1440.       (delete-region mb me)
  1441.       (goto-char mb)
  1442.       ;; Dispense with number if numbered-bullet prefix:
  1443.       (if (and outline-numbered-bullet
  1444.                (string= outline-numbered-bullet current-bullet)
  1445.                (looking-at "[0-9]+"))
  1446.           (delete-region (match-beginning 0)(match-end 0)))
  1447.  
  1448.       ;; Put in new prefix:
  1449.       (insert-string new-prefix)
  1450.       )
  1451.  
  1452.     ;; Reindent the body if elected and depth changed:
  1453.     (if (and outline-reindent-bodies
  1454.              (not (= new-depth current-depth)))
  1455.         (outline-reindent-body current-depth new-depth))
  1456.  
  1457.     ;; Recursively rectify successive siblings if selected:
  1458.     (if do-successors
  1459.         (save-excursion
  1460.           (while (outline-next-sibling)
  1461.             (setq index
  1462.                   (cond ((numberp index) (1+ index))
  1463.                         ((not number-control)  (outline-sibling-index))))
  1464.             (if (outline-numbered-type-prefix)
  1465.                 (outline-rebullet-heading nil        ;;; solicit
  1466.                                           new-depth    ;;; new-depth
  1467.                                           number-control;;; number-control
  1468.                                           index        ;;; index
  1469.                                           nil)))))    ;;;(dont!)do-successors
  1470.       )
  1471.   )
  1472.  
  1473. (defun outline-rebullet-topic (arg)
  1474.   "   Like outline-rebullet-topic-grunt, but start from visible one at point.
  1475.    Descends into invisible as well as visible topics, however.
  1476.  
  1477.    With repeat count, shift topic depth by that amount."
  1478.   (interactive "P")
  1479.   (let ((start-col (current-column))
  1480.         (was-eol (eolp)))
  1481.     (save-excursion
  1482.       ;; Normalize arg:
  1483.       (cond ((null arg) (setq arg 0))
  1484.             ((listp arg) (setq arg (car arg))))
  1485.       ;; Fill the user in, in case we're shifting a big topic:
  1486.       (if (not (zerop arg)) (message "Shifting..."))
  1487.       (outline-back-to-current-heading)
  1488.       (if (<= (+ (outline-recent-depth) arg) 0)
  1489.           (error "Attempt to shift topic below level 1"))
  1490.       (outline-rebullet-topic-grunt arg)
  1491.       (if (not (zerop arg)) (message "Shifting... done.")))
  1492.     (move-to-column (+ start-col arg)))
  1493.   )
  1494. (defun outline-rebullet-topic-grunt (&optional relative-depth
  1495.                                                starting-depth
  1496.                                                starting-point
  1497.                                                index
  1498.                                                do-successors)
  1499.  
  1500.   "   Rebullet the topic at point, visible or invisible, and all
  1501.    contained subtopics.  See outline-rebullet-heading for rebulleting
  1502.    behavior.
  1503.  
  1504.    All arguments are optional.
  1505.  
  1506.    First arg RELATIVE-DEPTH means to shift the depth of the entire
  1507.    topic that amount.
  1508.  
  1509.    The rest of the args are for internal recursive use by the function
  1510.    itself.  The are STARTING-DEPTH, STARTING-POINT, and INDEX."
  1511.  
  1512.   (let* ((relative-depth (or relative-depth 0))
  1513.          (new-depth (outline-depth))
  1514.          (starting-depth (or starting-depth new-depth))
  1515.          (on-starting-call  (null starting-point))
  1516.          (index (or index
  1517.                     ;; Leave index null on starting call, so rebullet-heading
  1518.                     ;; calculates it at what might be new depth:
  1519.                     (and (or (zerop relative-depth)
  1520.                              (not on-starting-call))
  1521.                          (outline-sibling-index))))
  1522.          (moving-outwards (< 0 relative-depth))
  1523.          (starting-point (or starting-point (point))))
  1524.  
  1525.     ;; Sanity check for excessive promotion done only on starting call:
  1526.     (and on-starting-call
  1527.          moving-outwards
  1528.          (> 0 (+ starting-depth relative-depth))
  1529.          (error "Attempt to shift topic out beyond level 1."))    ;;; ====>
  1530.  
  1531.     (cond ((= starting-depth new-depth)
  1532.            ;; We're at depth to work on this one:
  1533.            (outline-rebullet-heading nil        ;;; solicit
  1534.                                      (+ starting-depth    ;;; starting-depth
  1535.                                         relative-depth)
  1536.                                      nil        ;;; number
  1537.                                      index        ;;; index
  1538.                                      ;; Every contained topic will get hit,
  1539.                                      ;; and we have to get to outside ones
  1540.                                      ;; deliberately:
  1541.                                      nil)        ;;; do-successors
  1542.            ;; ... and work on subsequent ones which are at greater depth:
  1543.            (setq index 0)
  1544.            (outline-next-heading)
  1545.            (while (and (not (eobp))
  1546.                        (< starting-depth (outline-recent-depth)))
  1547.              (setq index (1+ index))
  1548.              (outline-rebullet-topic-grunt relative-depth   ;;; relative-depth
  1549.                                            (1+ starting-depth);;;starting-depth
  1550.                                            starting-point   ;;; starting-point
  1551.                                            index)))        ;;; index
  1552.  
  1553.           ((< starting-depth new-depth)
  1554.            ;; Rare case - subtopic more than one level deeper than parent.
  1555.            ;; Treat this one at an even deeper level:
  1556.            (outline-rebullet-topic-grunt relative-depth   ;;; relative-depth
  1557.                                          new-depth      ;;; starting-depth
  1558.                                          starting-point      ;;; starting-point
  1559.                                          index)))      ;;; index
  1560.  
  1561.     (if on-starting-call
  1562.         (progn
  1563.           ;; Rectify numbering of former siblings of the adjusted topic,
  1564.           ;; if topic has changed depth
  1565.           (if (or do-successors
  1566.                   (and (not (zerop relative-depth))
  1567.                        (or (= (outline-recent-depth) starting-depth)
  1568.                            (= (outline-recent-depth) (+ starting-depth
  1569.                                                         relative-depth)))))
  1570.               (outline-rebullet-heading nil nil nil nil t))
  1571.           ;; Now rectify numbering of new siblings of the adjusted topic,
  1572.           ;; if depth has been changed:
  1573.           (progn (goto-char starting-point)
  1574.                  (if (not (zerop relative-depth))
  1575.                      (outline-rebullet-heading nil nil nil nil t)))))
  1576.     )
  1577.   )
  1578. (defun outline-number-siblings (&optional denumber)
  1579.   "   Assign numbered topic prefix to this topic and its siblings.
  1580.  
  1581.    With universal argument, denumber - assign default bullet to this
  1582.    topic and its siblings.
  1583.  
  1584.    With repeated universal argument (`^U^U'), solicit bullet for each
  1585.    rebulleting each topic at this level."
  1586.  
  1587.   (interactive "P")
  1588.  
  1589.   (save-excursion
  1590.     (outline-back-to-current-heading)
  1591.     (outline-beginning-of-level)
  1592.     (let ((index (if (not denumber) 1))
  1593.           (use-bullet (equal '(16) denumber))
  1594.           (more t))
  1595.       (while more
  1596.         (outline-rebullet-heading use-bullet        ;;; solicit
  1597.                                   nil            ;;; depth
  1598.                                   t            ;;; number-control
  1599.                                   index            ;;; index
  1600.                                   nil)            ;;; do-successors
  1601.         (if index (setq index (1+ index)))
  1602.         (setq more (outline-next-sibling)))
  1603.       )
  1604.     )
  1605.   )
  1606.  
  1607.  
  1608. (defun outline-shift-in (arg)
  1609.   "   Decrease prefix depth of current heading and any topics collapsed
  1610.    within it."
  1611.   (interactive "p")
  1612.   (outline-rebullet-topic arg))
  1613. (defun outline-shift-out (arg)
  1614.   "   Decrease prefix depth of current heading and any topics collapsed
  1615.    within it."
  1616.   (interactive "p")
  1617.   (outline-rebullet-topic (* arg -1)))
  1618.  
  1619. ;;;-------------------------------------------------------------------------
  1620. ;;; Outline topic creation forms:
  1621.  
  1622. (defun open-topic (depth &optional open-prior get-alternate-bullet)
  1623.   "   Open new topic header at DEPTH, after the end of the current topic
  1624.    at that depth (including any subtopics).  The new topic gets a leading
  1625.    blank line if the initial topic at the depth has one before it.
  1626.  
  1627.    If optional arg PRIOR is non-nil, open just prior to the current
  1628.    topic at specified depth.
  1629.  
  1630.    Non-nil optional third argument, GET-ALTERNATE-BULLET, causes
  1631.    solicitation from the user of the choice of bullet.
  1632.  
  1633.    The first line of a topic is distinguished by a topic prefix at the
  1634.    beginning of the line.  A normal topic prefix consists of either
  1635.    the first character on 'outline-bullets-string' (typically an
  1636.    asterisk - '*'), or else a period ('.') followed by zero or more
  1637.    spaces and then one of the characters in 'outline-bullets-string'.
  1638.    Thus the topic depth for a given prefix is equal to the number of
  1639.    spaces + 2 (for the asterisk and period).
  1640.  
  1641.    The form and content of the topic prefix produced depends on a few
  1642.    things:
  1643.  
  1644.    - The top level prefix is always an asterisk ('*')
  1645.    - 'outline-old-style-prefixes' setting - if nil (default) then
  1646.      non-top-level prefixes are 'space-padded', nil means all
  1647.      asterisks.
  1648.    - Space padded prefixes for level n start with a dot ('.'), followed
  1649.      by n-2 spaces, followed by a bullet from among the characters on
  1650.      'outline-bullets-string'.  The choice of bullets for space padded
  1651.      prefixes depends on some additional factors:
  1652.  
  1653.      - With an exception (see next item), the default bullet produced
  1654.        depends on the value of 'outline-stylish-prefixes' - if nil
  1655.        then an asterisk is used.  If t (default) then the bullet is
  1656.        selected from 'outline-plain-bullets -string' modulo the topic
  1657.        depth.
  1658.      - If 'outline-numbered-bullets' has a string value, then any
  1659.        topic which uses that bullet is numbered by open-topic, it is
  1660.        preserved through adjustment by 'outline-rebullet-heading' and
  1661.        'outline-rebullet-topic', and topics opened immediately after
  1662.        and at the same level of a numbered heading are created as
  1663.        numbered headings.
  1664.  
  1665.    All supported topic prefix styles are respected by the maneuvering
  1666.    functions regardless of the configuration variable settings.
  1667.  
  1668.    The '...-old-style-...' setting provides complete backwards
  1669.    compatability with the original outline-mode, permitting use of the
  1670.    new topic minting, reforming, and depth-adjusting functions while
  1671.    maintaining consistency with the old format."
  1672.  
  1673.   (let ((open-on-blank (if (looking-at "^$") (point)))
  1674.         (this-depth (outline-depth)))
  1675.     (if (> this-depth depth)
  1676.         (outline-ascend-to-depth depth)
  1677.       (outline-back-to-current-heading))
  1678.     (let* ((index (save-excursion
  1679.                     (if open-on-blank (goto-char open-on-blank))
  1680.                     (+ (outline-sibling-index depth) (if open-prior 0 1))))
  1681.            (new-prefix
  1682.             (concat (outline-make-topic-prefix nil ;prior-bullet
  1683.                                                t ;new
  1684.                                                depth ;depth
  1685.                                                get-alternate-bullet ;solicit
  1686.                                                nil ;number-control
  1687.                                                index) ;index
  1688.                     " ")))
  1689.  
  1690.       ;; We're at topic header, position cursor for opening:
  1691.       (cond (open-prior (if (bobp) (open-line 1) (forward-char -1)))
  1692.             (open-on-blank (goto-char open-on-blank)) ;; open on this line.
  1693.             ;; open just after any topics at depth greater than requested:
  1694.             (t (if (> depth (outline-depth))
  1695.                    ;; Embedded new topics are snugged up to subtree:
  1696.                    (progn (outline-next-preface) (end-of-line))
  1697.                  ;; ... while sibling and greater get whitespace
  1698.                  ;; before if there's already some there:
  1699.                  (outline-end-of-current-subtree)
  1700.                  (end-of-line))))
  1701.  
  1702.       (cond (open-on-blank)
  1703.             ((< this-depth depth)
  1704.              (if (bolp) (open-line 1) (newline 1)))
  1705.             ;; If current topic at depth has a blank line before and
  1706.             ;; after it, provide blank lines around the new one, too.
  1707.             ;; Next two cases for this.
  1708.             ((and open-prior
  1709.                   (save-excursion
  1710.                     (beginning-of-line)
  1711.                     (if (not (bobp)) (outline-ascend-to-depth depth))
  1712.                     (looking-at "[\C-j ]*$")))
  1713.              (newline 1)(open-line 1))
  1714.             ;; Blank lines around current topic, make blanks around new one:
  1715.             ((save-excursion
  1716.                (beginning-of-line)
  1717.                (and (outline-ascend-to-depth depth)
  1718.                     (or (bobp)
  1719.                         (and (forward-char -1)
  1720.                              (re-search-backward "^" nil t)
  1721.                              (looking-at "[\C-j ]*$")))
  1722.                     (looking-at "\C-j[\C-i ]*$")))
  1723.              (newline 2))
  1724.             ((newline 1)))
  1725.  
  1726.       ;; Put the new topic header prefix in place:
  1727.       (insert-string new-prefix)
  1728.  
  1729.       ;; Show the new entry, to give quick feedback even if we're
  1730.       ;; really still working on the subsequent renumbering:
  1731.       ;; (bet peoply mostly don't notice the lag once they get the response!)
  1732.       (sit-for 0)
  1733.  
  1734.       ;; And renumber the new topic, and successive siblings if any,
  1735.       ;; if the new topic was at a different level than topic from
  1736.       ;; which we opened:
  1737.       (save-excursion
  1738.         (if (or (> this-depth depth)
  1739.                 ;; Not going outwards, don't have to redo current one:
  1740.                 (outline-next-sibling))
  1741.             (outline-rebullet-heading nil        ;;; solicit
  1742.                                       depth         ;;; depth
  1743.                                       nil         ;;; number-control
  1744.                                       nil        ;;; index
  1745.                                       t))        ;;; do-successors
  1746.         )
  1747.       )
  1748.     )
  1749.   )
  1750.  
  1751. (defun open-subtopic (arg)
  1752.   "   Open new topic header at deeper level than the current one.
  1753.  
  1754.   Negative universal arg means to open deeper, but place the new topic
  1755.   prior to the current one."
  1756.   (interactive "p")
  1757.   (open-topic (+ (outline-current-depth) 1)
  1758.                (> 0 arg)
  1759.                (not (= (if (< arg 0) (- arg) arg) 1))))
  1760. (defun open-sibtopic (arg)
  1761.   "   Open new topic header at same level as the current one.  Negative
  1762.   universal arg means to place the new topic prior to the current
  1763.   one."
  1764.   (interactive "p")
  1765.   (open-topic (outline-current-depth)
  1766.               (> 0 arg)
  1767.               (not (= (if (< arg 0) (- arg) arg) 1))))
  1768. (defun open-supertopic (arg)
  1769.   "   Open new topic header at shallower level than the current one.
  1770.   Negative universal arg means to open shallower, but place the new
  1771.   topic prior to the current one."
  1772.  
  1773.   (interactive "p")
  1774.   (open-topic (- (outline-current-depth) 1)
  1775.               (> 0 arg)
  1776.               (not (= (if (< arg 0) (- arg) arg) 1))))
  1777.  
  1778. ;;;-------------------------------------------------------------------------
  1779. ;;; Surgery (kill-ring) functions with special provisions for outlines:
  1780.  
  1781. (defun outline-kill-line (&optional arg)
  1782.   "   Kill line, adjusting subsequent lines suitably for outline mode."
  1783.  
  1784.   (interactive "*P")
  1785.   (if (not (and outline-numbered-bullet (bolp) (looking-at outline-regexp)))
  1786.       (kill-line arg)
  1787.     (let* ((depth (outline-depth))
  1788.            (ascender depth))
  1789.       (kill-line arg)
  1790.       (sit-for 0)
  1791.       (if (> (outline-depth) depth)
  1792.           ;; An intervening parent was removed from after a subtree:
  1793.           (setq depth (outline-recent-depth)))
  1794.       (save-excursion
  1795.         (while (and (> (outline-depth) 0)
  1796.                     (> (outline-recent-depth) ascender)
  1797.                     (outline-ascend-to-depth (setq ascender (1- ascender)))))
  1798.             ;; Have to try going forward until we find another at
  1799.             ;; desired depth:
  1800.         (if (and outline-numbered-bullet
  1801.                  (outline-descend-to-depth depth))
  1802.             (outline-rebullet-heading nil        ;;; solicit
  1803.                                       depth        ;;; depth
  1804.                                       nil         ;;; number-control
  1805.                                       nil        ;;; index
  1806.                                       t)        ;;; do-successors
  1807.           )
  1808.         )
  1809.       )
  1810.     )
  1811.   )
  1812. (defun outline-kill-topic ()
  1813.   "   Kill topic together with subtopics."
  1814.  
  1815.   ;; Some finagling is done to make complex topic kills appear faster
  1816.   ;; than they actually are.  A redisplay is performed immediately
  1817.   ;; after the region is disposed of, though the renumbering process
  1818.   ;; has yet to be performed.  This means that there may appear to be
  1819.   ;; a lag *after* the kill has been performed.
  1820.  
  1821.   (interactive)
  1822.   (let* ((beg (outline-back-to-current-heading))
  1823.          (depth (outline-recent-depth)))
  1824.     (outline-end-of-current-subtree)
  1825.     (if (not (eobp))
  1826.         (forward-char 1))
  1827.     (kill-region beg (point))
  1828.     (sit-for 0)
  1829.     (save-excursion
  1830.       (if (and outline-numbered-bullet
  1831.                (outline-descend-to-depth depth))
  1832.           (outline-rebullet-heading nil        ;;; solicit
  1833.                                     depth    ;;; depth
  1834.                                     nil        ;;; number-control
  1835.                                     nil        ;;; index
  1836.                                     t)        ;;; do-successors
  1837.         )
  1838.       )
  1839.     )
  1840.   )
  1841.  
  1842. (defun outline-yank (&optional arg)
  1843.   "   Like regular yank, except does depth adjustment of yanked topics, when:
  1844.  
  1845.    1 the stuff being yanked starts with a valid outline header prefix, and
  1846.    2 it is being yanked at the end of a line which consists of only a valid
  1847.      topic prefix.
  1848.  
  1849.    If these two conditions hold then the depth of the yanked topics
  1850.    are all adjusted the amount it takes to make the first one at the
  1851.    depth of the header into which it's being yanked.
  1852.  
  1853.    The point is left in from of yanked, adjusted topics, rather than
  1854.    at the end (and vice-versa with the mark).  Non-adjusted yanks,
  1855.    however, (ones that don't qualify for adjustment) are handled
  1856.    exactly like normal yanks.
  1857.  
  1858.    Outline-yank-pop is used with outline-yank just as normal yank-pop
  1859.    is used with normal yank in non-outline buffers."
  1860.  
  1861.   (interactive "*P")
  1862.   (setq this-command 'yank)
  1863.   (let ((beginning (point))
  1864.         established-depth)      ; Depth of the prefix into which we're yanking.
  1865.     ;; Get current depth and numbering ... Oops, not doing anything
  1866.     ;; with the number just yet...
  1867.     (if (and (eolp)
  1868.              (save-excursion (beginning-of-line)
  1869.                              (looking-at outline-regexp)))
  1870.         (setq established-depth (- (match-end 0) (match-beginning 0))))
  1871.     (yank arg)
  1872.     (exchange-dot-and-mark)
  1873.     (if (and established-depth          ; the established stuff qualifies.
  1874.              ;; The yanked stuff also qualfies - is topic(s):
  1875.              (looking-at (concat "\\(" outline-regexp "\\)")))
  1876.         ;; Ok, adjust the depth of the yanked stuff.  Note that the
  1877.         ;; stuff may have more than a single root, so we have to
  1878.         ;; iterate over all the top level ones yanked, and do them in
  1879.         ;; such a way that the adjustment of one new one won't affect
  1880.         ;; any of the other new ones.  We use the focus of the
  1881.         ;; narrowed region to successively exclude processed siblings.
  1882.         (let* ((yanked-beg (match-beginning 1))
  1883.                (yanked-end (match-end 1))
  1884.                (yanked-depth (- yanked-end yanked-beg))
  1885.                (depth-diff (- established-depth yanked-depth))
  1886.                done
  1887.                (more t))
  1888.           (save-excursion
  1889.             (save-restriction
  1890.               (narrow-to-region yanked-beg (mark))
  1891.               ;; First trim off excessive blank line at end, if any:
  1892.               (goto-char (point-max))
  1893.               (if (looking-at "^$") (delete-char -1))
  1894.               (goto-char (point-min))
  1895.               ;; Work backwards, with each shallowest level,
  1896.               ;; successively excluding the last processed topic
  1897.               ;; from the narrow region:
  1898.               (goto-char (point-max))
  1899.               (while more
  1900.                 (outline-back-to-current-heading)
  1901.                 ;; go as high as we can in each bunch:
  1902.                 (while (outline-ascend-to-depth
  1903.                         (1- (outline-depth))))
  1904.                 (save-excursion
  1905.                   (outline-rebullet-topic-grunt depth-diff
  1906.                                                 (outline-depth)
  1907.                                                 (point)))
  1908.                 (if (setq more (not (bobp)))
  1909.                     (progn (widen)
  1910.                            (forward-char -1)
  1911.                            (narrow-to-region yanked-beg (point)))))))
  1912.           ;; Now dispose of old prefix...
  1913.           (delete-region yanked-beg
  1914.                          (+ yanked-beg established-depth))
  1915.           ;; and extraneous digits and a space:
  1916.           (while (looking-at "[0-9]") (delete-char 1))
  1917.           (if (looking-at " ") (delete-char 1))
  1918.           )
  1919.       (exchange-dot-and-mark))
  1920.     (if outline-numbered-bullet
  1921.         (progn
  1922.           ;; Renumber, in case necessary:
  1923.           (sit-for 0)
  1924.           (save-excursion
  1925.             (goto-char beginning)
  1926.             (if (outline-goto-prefix)
  1927.                 (outline-rebullet-heading nil        ;;; solicit
  1928.                                           (outline-depth) ;;; depth
  1929.                                           nil        ;;; number-control
  1930.                                           nil        ;;; index
  1931.                                           t)        ;;; do-successors
  1932.                   )
  1933.             )
  1934.           )
  1935.       )
  1936.     )
  1937.   )
  1938. (defun outline-yank-pop (&optional arg)
  1939.   "   Just like yank-pop, but works like outline-yank when popping
  1940.   topics just after fresh outline prefixes.  Adapts level of popped
  1941.   stuff to level of fresh prefix."
  1942.  
  1943.   (interactive "*p")
  1944.   (if (not (eq last-command 'yank))
  1945.       (error "Previous command was not a yank"))
  1946.   (setq this-command 'yank)
  1947.   (delete-region (point) (mark))
  1948.   (rotate-yank-pointer arg)
  1949.   (outline-yank)
  1950.   )
  1951.  
  1952. ;;;-------------------------------------------------------------------------
  1953. ;;; isearch wrappers for special outline provisions:
  1954.  
  1955. (defvar outline-search-reconceal nil
  1956.   "Used for outline isearch provisions, to track whether current search
  1957. match was concealed outside of search.  The value is the location of the
  1958. match, if it was concealed, regular if the entire topic was concealed, in
  1959. a list if the entry was concealed.")
  1960. (defun outline-enwrap-isearch ()
  1961.   "   Impose isearch-mode wrappers so isearch progressively exposes and
  1962.    reconceals hidden topics when working in outline mode, but works
  1963.    elsewhere.
  1964.  
  1965.    The function checks to ensure that the rebindings are done only once"
  1966.   ;; Make sure isearch-mode is loaded,
  1967.   (if (or (not outline-enwrap-isearch-mode)
  1968.           (fboundp 'real-isearch-quit))
  1969.       nil
  1970.     (if (not (and (fboundp 'isearch-mode)
  1971.                   (fboundp 'isearch-quit)))
  1972.         (load-library "isearch-mode.el"))
  1973.     ;; stash the crux-point functions so they're in known places, then
  1974.     ;; register the wrapper functions under their old names, instead:
  1975.     (fset 'real-isearch-quit (symbol-function 'isearch-quit))
  1976.     (fset 'isearch-quit 'isearch-quit/outline-provisions)
  1977.     (fset 'real-isearch-done (symbol-function 'isearch-done))
  1978.     (fset 'isearch-done 'isearch-done/outline-provisions)
  1979.     (fset 'real-isearch-update (symbol-function 'isearch-update))
  1980.     (fset 'isearch-update 'isearch-update/outline-provisions)
  1981.     (make-local-variable 'outline-search-reconceal))
  1982.   )
  1983. (defun outline-isearch-arrival-business ()
  1984.   "   Do outline business like exposing current point, if necessary,
  1985.    registering reconceal state accordingly."
  1986.   (setq outline-search-reconceal
  1987.         (if (outline-hidden-p)
  1988.             ;; set to just point if the entire topic is hidden, or is
  1989.             ;; supposed to be hidden (according to already pending
  1990.             ;; setting of outline-search-reconceal), or point in a list
  1991.             ;; if just part of the entry is hidden:
  1992.             (save-excursion (outline-goto-prefix)
  1993.                             (prog1 (if (outline-hidden-p)
  1994.                                         (point)
  1995.                                       (list (point)))
  1996.                               (outline-show-entry)))
  1997.             )
  1998.     )
  1999.   )
  2000. (defun outline-isearch-advancing-business ()
  2001.   "   Do outline business like deexposing current point, if necessary,
  2002.    according to reconceal state registration."
  2003.   (if outline-search-reconceal
  2004.       (save-excursion
  2005.         (if (listp outline-search-reconceal)
  2006.             ;; Leave the topic visible:
  2007.             (progn (goto-char (car outline-search-reconceal))
  2008.                    (outline-hide-current-entry))
  2009.           ;; Rehide the entire topic:
  2010.           (goto-char outline-search-reconceal)
  2011.           (outline-hide-current-entry-completely))))
  2012.   )
  2013.  
  2014. (defun isearch-quit/outline-provisions ()
  2015.   (interactive)
  2016.   (if (and outline-enwrap-isearch-mode
  2017.            (string= mode-name "Outline"))
  2018.       (outline-isearch-advancing-business))
  2019.   (real-isearch-quit))
  2020. (defun isearch-done/outline-provisions ()
  2021.   (interactive)
  2022.   (if (and outline-enwrap-isearch-mode
  2023.            (string= mode-name "Outline"))
  2024.       (save-excursion
  2025.         (if (and outline-search-reconceal
  2026.                  (not (listp outline-search-reconceal)))
  2027.             ;; The topic was concealed - reveal it, its siblings,
  2028.             ;; and any ancestors that are still concealed:
  2029.             (progn (message "(exposing destination)")(sit-for 0)
  2030.                    (outline-ascend-to-depth (1- (outline-depth)))
  2031.                    ;; Ensure that the target topic's ancestors are exposed
  2032.                    (while (outline-hidden-p) (outline-show-current-children))
  2033.                    ;; Ensure target topic's siblings are exposed:
  2034.                    (outline-show-current-children)))
  2035.         (outline-isearch-arrival-business)))
  2036.   (real-isearch-done)
  2037.   )
  2038. (defun isearch-update/outline-provisions ()
  2039.   "    Wrapper around isearch which exposes and conceals hidden outline
  2040.    portions encountered in the course of searching."
  2041.   (if (not (and outline-enwrap-isearch-mode
  2042.                 (string= mode-name "Outline")))
  2043.       ;; Just do the plain business:
  2044.       (real-isearch-update)
  2045.  
  2046.     ;; Ah - provide for outline conditions:
  2047.     (outline-isearch-advancing-business)
  2048.     (real-isearch-update)
  2049.     (cond (isearch-success (outline-isearch-arrival-business))
  2050.           ((not isearch-success) (outline-isearch-advancing-business)))
  2051.     )
  2052.   )
  2053.  
  2054.  
  2055.  
  2056. ;;;-------------------------------------------------------------------------
  2057. ;;; Scattered and Sundries
  2058.  
  2059. (defun outline-copy-exposed (&optional workbuf)
  2060.   "   Duplicate buffer to other buffer, sans hidden stuff.
  2061.  
  2062.    Without repeat count, this simple-minded function just generates
  2063.    the new buffer by concatenating the current buffer name with \"
  2064.    exposed\", and doing a 'get-buffer' on it."
  2065.  
  2066.   (interactive)
  2067.   (if (not workbuf) (setq workbuf (concat (buffer-name) " exposed")))
  2068.   (let ((buf (current-buffer)))
  2069.     (if (not (get-buffer workbuf))
  2070.     (generate-new-buffer workbuf))
  2071.     (pop-to-buffer workbuf)
  2072.     (erase-buffer)
  2073.     (insert-buffer buf)
  2074.     (replace-regexp "\^M[^\^M\^J]*" "")
  2075.     (goto-char (point-min))
  2076.     )
  2077.   )
  2078.  
  2079. (defun outlineify-sticky ()
  2080.   "   Activate outline mode and establish an -*-outline-*- explicit mode
  2081.    trigger in buffer."
  2082.   (interactive)
  2083.   (outline-mode)
  2084.   (save-excursion
  2085.     (goto-char 0)
  2086.     (if (not (looking-at ".*-\*-outline-*-"))
  2087.     (insert "* -*-outline-*-\n" ))))
  2088.                                         
  2089. ;; Change history
  2090. ;;; Dec 91    V 1.1 released to usenet
  2091. ;;; later in dec, 91 eliminated reference to 'cl.el' macro, 'case'
  2092. ;;;             (thanks to XXX for pointing out the dependency).
  2093. ;;;  8-Jan-1992 Eliminated reference to 'cl.el' func, 'abs' (thanks to
  2094. ;;;        jmm@king.econ.lsa.umich.edu for pointing out this dependency).
  2095. ;;;  8-Jan-1992 Put in "?\(" instead of "40" (thanks to liberte@cs.uiuc.edu
  2096. ;;;        for filling me in on this way to accomodate emacs lisp syntax).
  2097. ;;;  9-Jan-1992 V1.2
  2098. ;;;  9-Mar-1992 V1.3
  2099. ;;; 11-Apr-1992 V2.0 'allout.el'
  2100. ;;; 11-Apr-1992 V2.1 Several bug fixes.  Released to LCD.
  2101.