File: hideshow.el.html
* Commands provided
This file provides the Hideshow minor mode, it includes the following commands (and their keybindings) to hiding and showing code and comment blocks:
hs-hide-block C-c @ C-h/C-d
hs-show-block C-c @ C-s
hs-hide-all C-c @ C-M-h/C-t
hs-show-all C-c @ C-M-s/C-a
hs-hide-level C-c @ C-l
hs-toggle-hiding C-c @ C-c/C-e or S-<mouse-2>
hs-hide-initial-comment-block
hs-cycle C-c @ TAB
hs-toggle-all C-c @ <backtab>
All these commands are defined in hs-prefix-map(var)/hs-prefix-map(fun),
hs-minor-mode-map and hs-indicators-map.
Blocks are defined per mode. For example, in c-mode and similar, 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
buffer-local.
* Suggested usage
Add the following to your init file:
(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)))
* Customization
Hideshow provides the following user options:
- hs-hide-comments-when-hiding-all
If non-nil, hs-hide-all, hs-cycle and hs-hide-level will hide
comments too.
- hs-hide-all-non-comment-function
If non-nil, after calling hs-hide-all, this function is called
with no arguments.
- hs-isearch-open
What kind of hidden blocks to open when doing isearch.
- hs-set-up-overlay
Function called with one arg (an overlay), intended to customize
the block hiding appearance.
- hs-display-lines-hidden
Displays the number of hidden lines next to the ellipsis.
- hs-show-indicators
Display indicators to show and toggle the block hiding.
- hs-indicator-type
Which indicator type should be used for the block indicators.
- hs-indicator-maximum-buffer-size
Max buffer size in bytes where the indicators should be enabled.
- hs-allow-nesting
If non-nil, hiding remembers internal blocks.
- hs-cycle-filter
Control where typing a TAB cycles the visibility.
The variable hs-hide-all-non-comment-function may be useful if you
only want to hide some N levels blocks for some languages/files or
implement your idea of what is more useful. For example, the
following code shows the next nested level in addition to the
top-level for java:
(defun ttn-hs-hide-level-2 ()
(when (funcall hs-looking-at-block-start-predicate)
(hs-hide-level 2)))
(add-hook 'java-mode-hook
(lambda ()
(setq-local hs-hide-all-non-comment-function
#'ttn-hs-hide-level-2)))
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)))
The following hooks are run after some commands:
hs-hide-hook => hs-hide-block hs-hide-all hs-hide-level hs-cycle
hs-show-hook => hs-show-block hs-show-all hs-cycle
The variable hs-set-up-overlay allow customize the appearance of
the hidden block and other effects associated with overlays. For
example:
(setopt 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)))))
* Extending hideshow
** Adding support for a major mode
Normally, hideshow tries to determine appropriate values for block
and comment definitions by examining the major mode settings. If the
major mode is not derived from prog-mode, hideshow will not
activate. If you want to override this, you can set any of the
following variables: hs-block-start-regexp,
hs-block-start-mdata-select, hs-block-end-regexp,
hs-c-start-regexp, hs-forward-sexp-function,
hs-adjust-block-beginning-function, hs-adjust-block-end-function,
hs-find-block-beginning-function, hs-find-next-block-function,
hs-looking-at-block-start-predicate, hs-inside-comment-predicate,
hs-treesit-things.
These variables help hideshow know what is considered a block, which function to use to get the block positions, etc.
A block is defined as text surrounded by hs-block-start-regexp and
hs-block-end-regexp.
For some major modes, forward-sexp does not work properly. In those
cases, hs-forward-sexp-function specifies another function to use
instead.
*** Tree-sitter support
All the treesit based modes already have support for hiding/showing
using the treesit thing list (see treesit-major-mode-setup).
However, for some modes the list thing is not enough for detecting
the proper code block and the range to hide, you can set the variable
hs-treesit-things to override this, but ensure you have the proper
values in hs-adjust-block-end-function and hs-adjust-block-beginning-function to
properly hide the code block.
** Migrating from hs-special-modes-alist
Starting with Emacs 31, hs-special-modes-alist has been deprecated.
Instead, modes should use the buffer-local variables that replace
each of the options in hs-special-modes-alist. The following table
shows the old elements of hs-special-modes-alist and their
replacement buffer-local variables:
Instead of this Use this
-----------------------------------------------------------------------
START hs-block-start-regexp
(START . MDATA) hs-block-start-regexp and hs-block-start-mdata-select
END hs-block-end-regexp
COMMENT-START hs-c-start-regexp
FORWARD-SEXP-FUNC hs-forward-sexp-function
ADJUST-BEG-FUNC hs-adjust-block-beginning-function
FIND-BLOCK-BEGINNING-FUNC hs-find-block-beginning-function
FIND-NEXT-BLOCK-FUNC hs-find-next-block-function
LOOKING-AT-BLOCK-START-P-FUNC hs-looking-at-block-start-predicate)
* 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 parenthesis.
The workaround is to clear hs-minor-mode-hook when byte-compiling:
(define-advice byte-compile-file (:around
(fn &rest rest)
byte-compile-file-hideshow-off)
(let (hs-minor-mode-hook)
(apply #'fn rest)))
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.
* 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 (author commentary)
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 (37)
hs-adjust-block-beginning | Function used to tweak the block beginning. |
hs-adjust-block-beginning-function | Function used to tweak the block beginning. |
hs-adjust-block-end-function | Function used to tweak the block end. |
hs-allow-nesting | If non-nil, hiding remembers internal blocks. |
hs-block-end-regexp | Regexp for end of block. |
hs-block-start-mdata-select | Element in ‘hs-block-start-regexp’ match data to consider as block start. |
hs-block-start-regexp | Regexp for beginning of block. |
hs-c-start-regexp | Regexp for beginning of comments. |
hs-cycle-filter | Control where typing a TAB cycles the visibility. |
hs-display-lines-hidden | If non-nil, display the number of hidden lines next to the ellipsis. |
hs-find-block-beginning-func | Function used to do ‘hs-find-block-beginning’. |
hs-find-block-beginning-function | Function used to do ‘hs-find-block-beginning’. |
hs-find-next-block-func | Function used to do ‘hs-find-next-block’. |
hs-find-next-block-function | Function used to do ‘hs-find-next-block’. |
hs-forward-sexp-func | Function used to do a ‘forward-sexp’. |
hs-forward-sexp-function | Function used to do a ‘forward-sexp’. |
hs-headline | Text of the line where a hidden block begins, set during isearch. |
hs-hide-all-non-comment-function | Function called if non-nil when doing ‘hs-hide-all’ for non-comments. |
hs-hide-block-behavior | How hideshow should hide a block. |
hs-hide-comments-when-hiding-all | Whether the comments should be hidden. |
hs-hide-hook | Hook called (with ‘run-hooks’) at the end of commands to hide text. |
hs-indicator-maximum-buffer-size | Max buffer size in bytes where the indicators should be enabled. |
hs-indicator-type | Indicate which indicator type to use for the block indicators. |
hs-indicators-map | Keymap for hideshow indicators. |
hs-inside-comment-predicate | Function used to check if point is inside a comment. |
hs-isearch-open | What kind of hidden blocks to open when doing ‘isearch’. |
hs-looking-at-block-start-p-func | Function used to do ‘hs-looking-at-block-start-p’. |
hs-looking-at-block-start-predicate | Function used to do ‘hs-looking-at-block-start-p’. |
hs-minor-mode | Non-nil if hs minor mode is enabled. |
hs-minor-mode-hook | Hook called when hideshow minor mode is activated or deactivated. |
hs-minor-mode-map | Keymap for hideshow minor mode. |
hs-minor-mode-menu | Menu used when hideshow minor mode is active. |
hs-prefix-map | Keymap for hideshow commands. |
hs-set-up-overlay | Function called with one arg, OV, a newly initialized overlay. |
hs-show-hook | Hook called (with ‘run-hooks’) at the end of commands to show text. |
hs-show-indicators | Whether hideshow should display block hide/show indicators. |
hs-treesit-things | Treesit things to check if point is at a valid block. |
Defined functions (42)
Defined faces (2)
hs-ellipsis | Face used for hideshow ellipsis. Note: If ‘selective-display’ ellipsis already has a face, hideshow will use that face for the ellipsis instead. |
hs-indicator-show | Face used in hideshow indicator to indicate a shown block. |