File: hideshow.el.html

* Commands provided

This file provides Hideshow Minor Mode. When active, nine commands are available, implementing block hiding and showing. They (and their keybindings) are:

  hs-hide-block C-c @ C-h
  hs-show-block C-c @ C-s
  hs-hide-all C-c @ C-M-h
  hs-show-all C-c @ C-M-s
  hs-hide-level C-c @ C-l
  hs-toggle-hiding C-c @ C-c
  hs-toggle-hiding S-<mouse-2>
  hs-hide-initial-comment-block

Blocks are defined per mode. In c-mode, c++-mode and java-mode, they are simply text between curly braces, while in Lisp-ish modes parens are used. Multi-line comment blocks can also be hidden. Read-only buffers are not a problem, since hideshow doesn't modify the text.

The command M-x hs-minor-mode toggles the minor mode or sets it
(similar to other minor modes).

* Suggested usage

Add the following to your init file:

    (require 'hideshow)
    (add-hook 'X-mode-hook #'hs-minor-mode) ; other modes similarly

where X = {emacs-lisp,c,c++,perl,...}. You can also manually toggle hideshow minor mode by typing M-x hs-minor-mode. After hideshow is activated or deactivated, hs-minor-mode-hook is run with run-hooks.

Additionally, Joseph Eydelnant writes:
  I enjoy your package hideshow.el Version 5.24 2001/02/13
  a lot and I've been looking for the following functionality:
  toggle hide/show all with a single key.
  Here are a few lines of code that lets me do just that.

    (defvar my-hs-hide nil "Current state of hideshow for toggling all.")
    ;;;###autoload
    (defun my-toggle-hideshow-all () "Toggle hideshow all."
      (interactive)
      (setq my-hs-hide (not my-hs-hide))
      (if my-hs-hide
          (hs-hide-all)
        (hs-show-all)))

[Your hideshow hacks here!]

* Customization

You can use M-x customize-variable on the following variables:

- hs-hide-comments-when-hiding-all -- self-explanatory!
- hs-hide-all-non-comment-function -- if non-nil, when doing a
                                        hs-hide-all, this function
                                        is called with no arguments
- hs-isearch-open -- what kind of hidden blocks to
                                        open when doing isearch

Some languages (e.g., Java) are deeply nested, so the normal behavior of hs-hide-all (hiding all but top-level blocks) results in very little information shown, which is not very useful. You can use the variable hs-hide-all-non-comment-function to implement your idea of what is more useful. For example, the following code shows the next nested level in addition to the top-level:

    (defun ttn-hs-hide-level-1 ()
      (when (hs-looking-at-block-start-p)
        (hs-hide-level 1))
      (forward-sexp 1))
    (setq hs-hide-all-non-comment-function 'ttn-hs-hide-level-1)

Hideshow works with incremental search (isearch) by setting the variable hs-headline, which is the line of text at the beginning of a hidden block that contains a match for the search. You can have this show up in the mode line by modifying the variable mode-line-format. For example, the following code prepends this info to the mode line:

    (unless (memq 'hs-headline mode-line-format)
      (setq mode-line-format
            (append '("-" hs-headline) mode-line-format)))

See documentation for mode-line-format for more info.

Hooks are run after some commands:

  hs-hide-hook in hs-hide-block, hs-hide-all, hs-hide-level
  hs-show-hook hs-show-block, hs-show-all

One of hs-hide-hook or hs-show-hook is run for the toggling commands when the result of the toggle is to hide or show blocks, respectively. All hooks are run with run-hooks. See the documentation for each variable or hook for more information.

Normally, hideshow tries to determine appropriate values for block and comment definitions by examining the buffer's major mode. If there are problems, hideshow will not activate and in that case you may wish to override hideshow's heuristics by adding an entry to variable hs-special-modes-alist. Packages that use hideshow should do something like:

  (add-to-list 'hs-special-modes-alist '(my-mode "{{" "}}" ...))

If you have an entry that works particularly well, consider submitting it for inclusion in hideshow.el. See docstring for hs-special-modes-alist for more info on the entry format.

See also variable hs-set-up-overlay for per-block customization of appearance or other effects associated with overlays. For example:

(setq hs-set-up-overlay
      (defun my-display-code-line-counts (ov)
        (when (eq 'code (overlay-get ov 'hs))
          (overlay-put ov 'display
                       (propertize
                        (format " ... <%d>"
                                (count-lines (overlay-start ov)
                                             (overlay-end ov)))
                        'face 'font-lock-type-face)))))

* Bugs

(1) Sometimes hs-headline can become out of sync. To reset, type
    M-x hs-minor-mode twice (that is, deactivate then re-activate
    hideshow).

(2) Some buffers can't be byte-compile-filed properly. This is because
    byte-compile-file inserts the file to be compiled in a temporary
    buffer and switches normal-mode on. In the case where you have
    hs-hide-initial-comment-block in hs-minor-mode-hook, the hiding of
    the initial comment sometimes hides parts of the first statement (seems
    to be only in normal-mode), so there are unbalanced "(" and ")".

    The workaround is to clear hs-minor-mode-hook when byte-compiling:

    (defadvice byte-compile-file (around
                                  byte-compile-file-hideshow-off
                                  act)
      (let ((hs-minor-mode-hook nil))
        ad-do-it))

(3) Hideshow interacts badly with Ediff and vc-diff. At the moment, the
    suggested workaround is to turn off hideshow entirely, for example:

    (add-hook 'ediff-prepare-buffer-hook #'turn-off-hideshow)
    (add-hook 'vc-before-checkin-hook #'turn-off-hideshow)

    In the case of vc-diff, here is a less invasive workaround:

    (add-hook 'vc-before-checkin-hook
              (lambda ()
                (goto-char (point-min))
                (hs-show-block)))

    Unfortunately, these workarounds do not restore hideshow state.
    If someone figures out a better way, please let me know.

* Correspondence

Correspondence welcome; please indicate version number. Send bug reports and inquiries to <ttn@gnu.org>.

* Thanks

Thanks go to the following people for valuable ideas, code and bug reports.

 Dean Andrews, Alf-Ivar Holm, Holger Bauer, Christoph Conrad, Dave Love,
 Dirk Herrmann, Gael Marziou, Jan Djarv, Guillaume Leray, Moody Ahmad,
 Preston F. Crow, Lars Lindberg, Reto Zimmermann, Keith Sheffield,
 Chew Meng Kuan, Tony Lam, Pete Ware, François Pinard, Stefan Monnier,
 Joseph Eydelnant, Michael Ernst, Peter Heslin

Special thanks go to Dan Nicolaescu, who reimplemented hideshow using overlays (rather than selective display), added isearch magic, folded in custom.el compatibility, generalized comment handling, incorporated mouse support, and maintained the code in general. Version 4.0 is largely due to his efforts.

* History

Hideshow was inspired when I learned about selective display. It was reimplemented to use overlays for 4.0 (see above). WRT older history, entries in the masterfile corresponding to versions 1.x and 2.x have been lost. XEmacs support is reliable as of 4.29. State save and restore was added in 3.5 (not widely distributed), and reliable as of
4.30. Otherwise, the code seems stable. Passes checkdoc as of 4.32.
Version 5.x uses new algorithms for block selection and traversal, unbundles state save and restore, and includes more isearch support.

Defined variables (22)

hs-adjust-block-beginningFunction used to tweak the block beginning.
hs-allow-nestingIf non-nil, hiding remembers internal blocks.
hs-block-end-regexpRegexp for end of block.
hs-block-start-mdata-selectElement in ‘hs-block-start-regexp’ match data to consider as block start.
hs-block-start-regexpRegexp for beginning of block.
hs-c-start-regexpRegexp for beginning of comments.
hs-find-block-beginning-funcFunction used to do ‘hs-find-block-beginning’.
hs-find-next-block-funcFunction used to do ‘hs-find-next-block’.
hs-forward-sexp-funcFunction used to do a ‘forward-sexp’.
hs-headlineText of the line where a hidden block begins, set during isearch.
hs-hide-all-non-comment-functionFunction called if non-nil when doing ‘hs-hide-all’ for non-comments.
hs-hide-comments-when-hiding-allHide the comments too when you do an ‘hs-hide-all’.
hs-hide-hookHook called (with ‘run-hooks’) at the end of commands to hide text.
hs-isearch-openWhat kind of hidden blocks to open when doing ‘isearch’.
hs-looking-at-block-start-p-funcFunction used to do ‘hs-looking-at-block-start-p’.
hs-minor-modeNon-nil if hs minor mode is enabled.
hs-minor-mode-hookHook called when hideshow minor mode is activated or deactivated.
hs-minor-mode-mapKeymap for hideshow minor mode.
hs-minor-mode-menuMenu used when hideshow minor mode is active.
hs-set-up-overlayFunction called with one arg, OV, a newly initialized overlay.
hs-show-hookHook called (with ‘run-hooks’) at the end of commands to show text.
hs-special-modes-alistAlist for initializing the hideshow variables for different modes.

Defined functions (29)

hs-already-hidden-p()
hs-c-like-adjust-block-beginning(INITIAL)
hs-discard-overlays(FROM TO)
hs-find-block-beginning()
hs-find-block-beginning-match()
hs-find-next-block(REGEXP MAXP COMMENTS)
hs-forward-sexp(MATCH-DATA ARG)
hs-grok-mode-type()
hs-hide-all()
hs-hide-block(&optional END)
hs-hide-block-at-point(&optional END COMMENT-REG)
hs-hide-comment-region(BEG END &optional REPOS-END)
hs-hide-initial-comment-block()
hs-hide-level(ARG)
hs-hide-level-recursive(ARG MINP MAXP)
hs-inside-comment-p()
hs-isearch-show(OV)
hs-isearch-show-temporary(OV HIDE-P)
hs-life-goes-on(&rest BODY)
hs-looking-at-block-start-p()
hs-make-overlay(B E KIND &optional B-OFFSET E-OFFSET)
hs-minor-mode(&optional ARG)
hs-minor-mode-menu(ARG1)
hs-mouse-toggle-hiding(&optional E)
hs-overlay-at(POSITION)
hs-show-all()
hs-show-block(&optional END)
hs-toggle-hiding(&optional E)
turn-off-hideshow()

Defined faces (0)