[comp.emacs] GNU Emacs outline-mode-hook source

gaynor@topaz.UUCP (05/01/87)

Hi...  I finally discovered outline mode!  This thrills you to no end,
I'm sure.  In preperation for making extensive use of it, though, I
wrote a hook for outline-mode that associates with `outline' buffers
their own outline-regexp and a human-readable description of that
regexp.  Also, it rebinds everything, and there are a couple of help
functions.

This doesn't do anything TOO fancy, like the recent fisheye-view
message I read.

I THINK I got all the bugs out, but if I missed any, please mail me
and I'll apologize and post the diffs.  Note that I am not the most
experienced GNU Emacs Lisp programmer, and if you see things that
could be done in a better way, or conventions not followed, or
`foo's not `bar'ed, or whatnot, PLEASE mail me and I will post the
diffs.

Also, there are default default-outline-regexp and
default-outline-description values that are set and used when these
aren't set.  These are kind of hard-coded in, and will require changes
in several spots.

The next thing to do is to write a function to easily modify the
outline-regexp stuff.

Hmm, come to think of it, I didn't write this with unwriteable buffers
in mind.  This shouldn't be a real big fix, I'll get the diffs out
when I get a chance.  The outline information is inserted into the
buffer at the top (when necessary) and then narrowed away, so it will
remain with the file when it's saved.

It's not so hard to use.  Find file (in a writeable buffer!), and go
into outline-mode.  The hook is autoloaded, no mess no fuss.  If
outline-regexp stuff needs to be inserted, this is when it's done.

I would suggest putting this in your .emacs, setting the 2nd (and 3rd?)
argument(s) of the autoload call appropriately:
======================================================================
(setq outline-mode-hook 'outline-mode-hook-function)
(autoload
  'outline-mode-hook-function
  "~/src/gnu-elisp/outline-mode-hook-function.el"
  "It makes a nice sandwhich.  A nice sandwhich.")
======================================================================

Here is the hook, and associated functions:
======================================================================
(defun describe-outline-mode ()
"Describes this version of outline-mode."
  (interactive)
  ;; Don't `restart' the buffer if it's already there.
  (if (get-buffer "*Outline Description*")
    ;; Yes, it changes the current buffer to *Outline Description*.
    (switch-to-buffer "*Outline Description*")
    (progn
      (switch-to-buffer "*Outline Description*")
      ;; This is the text of the buffer.  Remember to escape \s and "s!
      (insert
        (concat
"outline-regexp info
\\(    \\)*\\*\\([0-9]+\\([---.][0-9]+\\)*\\*\\|\\**\\) 
0 or more sequences of 4 blanks `    '
an asterisk `*'
choose either of
    alternative 1
        a digit-sequence (1 or more digits)
        0 or more sequences of
            a period `.' or a hyphen `-'
            a digit-sequence
        an asterisk `*'
    alternative 2
        0 or more asterisks `*'
end choice
finally, a blank ` '

*1* Help

    *1.1* C-c ? = describe-my-outline

        Select this buffer (`*Outline Commands*') if it exists,
        otherwise create it and fill it with this information.  Note
        that it is initially in outline mode (with the defaults),
        hence all of the commands work.  Use this buffer as a `proving
        grounds'.

    *1.2* C-c v = describe-outline-regexp-verbose

        This creates a help buffer containing the outline-regexp info
        (which is normally hidden from view).  The values of the LOCAL
        variables outline-regexp and outline-description.

    *1.3* C-c r = describe-outline-regexp

        Display the value of the LOCAL variable outline-regexp in the
        mini-buffer.

    *1.4* outline-regexp info

        Here's how to supply the values for outline-regexp and
        outline-regexp-description.  The first line of the file should
        contain `outline-regexp info', verbatim.  The second line
        should contain the value for the outline-regexp.  The third
        through n lines (optional) should be non-blank, containing a
        description (human readable) of outline-regexp.  Then, a blank
        line ends this section.  Now enter outline-mode, and this
        information will be processed and apparently disappear.
        Actually, it is 'narrowed away', to keep it out of sight.

        If you don't supply these values, default values are supplied.
        These defaults may be set, and are default-outline-regexp and
        default-outline-regexp-description.  If not set, they will be
        assigned values by the hook.

    *1.5* More Information

        See the Info entry Outline Mode for a discussion of
        outline-mode, and the Info entry on Narrowing for a discussion
        of selective text display.  See the Info entry on Regexps for
        a discussion of regular expressions.

*2* Movement

    *2.1* C-c n = outline-next-visible-heading

        Move the point to the next visible heading.

    *2.2* C-c p = outline-previous-visible-heading

        Move the point to the previous visible heading.

    *2.3* C-c u = outline-up-previous-heading

        Move the point to the parent heading.

    *2.4* C-c f = outline-forward-same-level

        Move point to the next sibling heading.

    *2.5* C-c b = outline-backward-same-level

        Move point to the previous sibling heading.

*3* Show

    *3.1* C-c s a = show-all

        Show everything in the outline.

    *3.2* C-c s s = show-subtree

        Show everything under under a heading.

    *3.3* C-c s b = show-branches

        Show all the sub-headings (ie branches) of a heading.

    *3.4* C-c s c = show-children

        Show the sub-headings (ie children's headings) of a heading.

    *3.5* C-c s . = show-entry

        Show the body of a heading.

*4* Hide

    *4.1* C-c h a = hide-body (more apropos - hide-all-leaves)

        Hide all leaves, showing only the branches.

    *4.2* C-c h s = hide-subtree

        Hide everything underneath the subtree.

    *4.3* C-c h l = hide-leaves

        Hide the leaves under a subtree, leaving only the branches.

    *4.4* C-c h . = hide-entry

        Hide the leaf at the current node.
")
      (outline-mode)
      (set-buffer-modified-p nil))))

(defun describe-outline-regexp-terse ()
"Show the value of outline-regexp in the mini-buffer."
  (interactive)
  (message (concat "outline-regexp = `" outline-regexp "'")))

(defun describe-outline-regexp-verbose ()
"Show the values of outline-regexp and outline-regexp-description
in their own buffer."
  (interactive)
  (with-output-to-temp-buffer "*Outline Regexp*"
    (princ (concat
              "outline-regexp = `"
              outline-regexp
              "'\n\nusage\n\n"
              outline-regexp-description))))

(defun outline-mode-hook-function ()
"An implementation of outline-mode that associates with each outline
file its own outline-regexp and outline-regexp-description.  It does
some rebinding, and a couple of help functions are bound.  I think
the next thing I'll want to do is make a convenient way to change
these values, rather than doing it lisply."

  ;; So that each buffer in outline mode may have it's own
  ;; outline-regexp and outline-regexp-description...
  (make-local-variable 'outline-regexp)
  (make-local-variable 'outline-regexp-description)

  ;; Now that proper variables exist locally, set their values.

  ;; Move the point to the end of the first line, kissing the old
  ;; point bye-bye.
  (goto-char (point-min))
  (end-of-line)

  ;; If the buffer contains outline-regexp info (ie if the first line
  ;; equal to "outline-regexp info"), ...
  (if (equal (buffer-substring (point-min) (point))
             "outline-regexp info")

    ;; ... then the values are there and must be extracted.
    (progn

      ;; First, get the value for outline-regexp by setting it to the
      ;; second line of the file (kissing the original mark bye-bye).
      (setq outline-regexp
        (buffer-substring
          (progn (forward-char 1) (point))
          (progn (end-of-line) (point))))

      ;; Second, get the value for outline-regexp-description to
      ;; everything from here on in + 1 to the next blank line.
      (setq outline-regexp-description
        (buffer-substring
          (1+ (point))
          (progn (search-forward "\n\n") (1- (point))))))

    ;; Otherwise, insert the default info and set the values.
    (progn
      (message "inserting default outline-regexp info...")
      (insert
        (concat
          "outline-regexp info\n"

          ;; If default-outline-regexp is bound, ...
          (if (boundp 'default-outline-regexp)
            ;; ... use it.
            (setq outline-regexp default-outline-regexp)
            ;; Otherwise, set it and use it.  Ie a default default value.
            (setq default-outline-regexp
              (setq outline-regexp
                "\\(    \\)*\\*\\([0-9]+\\([---.][0-9]+\\)*\\*\\|\\**\\) ")))

          ;; If default-outline-regexp-description is bound, ...
          (if (boundp 'default-outline-regexp-description)
            ;; ... use it.
            (setq outline-regexp-description
              default-outline-regexp-description)
            ;; Otherwise, set it and use it.  Ie a default default value.
            (setq default-outline-regexp-description
              (setq outline-regexp-description
                (concat
                  "0 or more sequences of 4 blanks `    '\n"
                  "an asterisk `*'\n"
                  "choose either\n"
                  "    alternative 1\n"
                  "        a digit-sequence (1 or more digits)\n"
                  "        0 or more sequences of\n"
                  "            a period `.' or a hyphen `-'\n"
                  "            a digit-sequence\n"
                  "        an asterisk `*'\n"
                  "    alternative 2\n"
                  "        0 or more asterisks `*'\n"
                  "end choice\n"
                  "finally, a blank ` '\n\n"))))))))

  ;; Now, narrow away (and hope it survives outline-mode)
  ;; everything up to point.  (Hindsight - it does.)
  (narrow-to-region (point) (point-max))

  ;; MY bindings.  Every defined function is bound.  Okay, so you may
  ;; frown at the 3-character sequences.  They're mnemonic and fairly
  ;; consistant between hides and shows.  Try them before you change
  ;; them.  THEN change them!

  ;; "C-cs" is the prefix for all the show commands.
  (local-unset-key "\C-cs")
  (define-key outline-mode-map "\C-csa" 'show-all)
  (define-key outline-mode-map "\C-css" 'show-subtree)
  (define-key outline-mode-map "\C-csb" 'show-branches)
  (define-key outline-mode-map "\C-csc" 'show-children)
  (define-key outline-mode-map "\C-cs." 'show-entry)

  ;; "C-ch" is the prefix for all the hide commands.
  (local-unset-key "\C-ch")
  (define-key outline-mode-map "\C-cha" 'hide-body)
  (define-key outline-mode-map "\C-chs" 'hide-subtree)
  (define-key outline-mode-map "\C-chl" 'hide-leaves)
  (define-key outline-mode-map "\C-ch." 'hide-entry)

  ;; The motion commands are fine as two-key sequences.
  (define-key outline-mode-map "\C-cn" 'outline-next-visible-heading)
  (define-key outline-mode-map "\C-cp" 'outline-previous-visible-heading)
  (define-key outline-mode-map "\C-cu" 'outline-up-heading)
  (define-key outline-mode-map "\C-cf" 'outline-forward-same-level)
  (define-key outline-mode-map "\C-cb" 'outline-backward-same-level)

  ;; The help commands are also find as two key sequences.
  (define-key outline-mode-map "\C-c?" 'describe-outline-mode)
  (define-key outline-mode-map "\C-cr" 'describe-outline-regexp-terse)
  (define-key outline-mode-map "\C-ct" 'describe-outline-regexp-terse)
  (define-key outline-mode-map "\C-cv" 'describe-outline-regexp-verbose))
======================================================================

       /-------------------------------------------------\
       | uucp:  ...!topaz!gaynor  ...!topaz!remus!gaynor |
       |        ~~~~~~~~~~~~~~~~                         |
       | arpa:  gaynor@topaz      silver@aim             |
       \-------------------------------------------------/

gaynor@topaz.UUCP (05/01/87)

The ORIGINAL doesn't work, even!  Yes, I'm embarressed <:^( .
Here are the mods:

line 10:  It's not really an error, but it messes up paren matching.
          Remove the second sentence.

line 135: I don't know how it happenned, but I lost a right-paren
          somewhow.  The `insert' that inserts the buffer contents in
          `describe-outline-mode' needs to be closed, so append a
          right-paren to the line.

I hate when things like this happen.

Andy "Oh sure, I'll just take one last look before posting..." Gaynor

       /-------------------------------------------------\
       | uucp:  ...!topaz!gaynor  ...!topaz!remus!gaynor |
       |        ~~~~~~~~~~~~~~~~                         |
       | arpa:  gaynor@topaz      silver@aim             |
       \-------------------------------------------------/