;;; hideshow.el --- minor mode cmds to selectively display code/comment blocks -*- lexical-binding:t -*- ;; Copyright (C) 1994-2025 Free Software Foundation, Inc. ;; Author: Thien-Thi Nguyen ;; Dan Nicolaescu ;; Keywords: C C++ java lisp tools editing comments blocks hiding outlines ;; Maintainer-Version: 5.65.2.2 ;; Time-of-Day-Author-Most-Likely-to-be-Recalcitrant: early morning ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; * 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- ;; `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 (funcall hs-looking-at-block-start-p-func) ;; (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-file'd 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 . ;; * 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. ;;; Code: (require 'mule-util) ; For `truncate-string-ellipsis' ;; For indicators (require 'icons) (require 'fringe) ;;--------------------------------------------------------------------------- ;; user-configurable variables (defgroup hideshow nil "Minor mode for hiding and showing program and comment blocks." :prefix "hs-" :group 'languages) (defface hs-ellipsis '((t :height 0.80 :box (:line-width -1) :inherit default)) "Face used for hideshow ellipsis. Note: If `selective-display' ellipsis already has a face, hideshow will use that face for the ellipsis instead." :version "31.1") (defface hs-indicator-hide '((t :inherit (shadow default))) "Face used in hideshow indicator to indicate a hidden block." :version "31.1") (defface hs-indicator-show '((t :inherit hs-indicator-hide :weight bold)) "Face used in hideshow indicator to indicate a shown block." :version "31.1") (defcustom hs-hide-comments-when-hiding-all t "Hide the comments too when you do an `hs-hide-all'." :type 'boolean) (defcustom hs-display-lines-hidden nil "If non-nil, display the number of hidden lines next to the ellipsis." :type 'boolean :version "31.1") (defcustom hs-minor-mode-hook nil "Hook called when hideshow minor mode is activated or deactivated." :type 'hook :version "21.1") (defcustom hs-isearch-open 'code "What kind of hidden blocks to open when doing `isearch'. One of the following symbols: code -- open only code blocks comment -- open only comment blocks t -- open both code and comment blocks nil -- open neither code nor comment blocks This has effect only if `search-invisible' is set to `open'." :type '(choice (const :tag "open only code blocks" code) (const :tag "open only comment blocks" comment) (const :tag "open both code and comment blocks" t) (const :tag "don't open any of them" nil))) (defcustom hs-show-indicators nil "Whether hideshow should display block hide/show indicators. If non-nil, hideshow will display indicators for toggling the visibility of code blocks. The indicators appearance are specified in `hs-indicator-type' (which see)." :type 'boolean :version "31.1") (defcustom hs-indicator-type 'fringe "Indicate which indicator type to use for the block indicators. The possible values can be: - `fringe', display the indicators in the fringe. - `margin', display the indicators in the margin. - nil, display the indicators at end-of-line. This only have effect if `hs-show-indicators' is non-nil." :type '(choice (const :tag "Fringes" fringe) (const :tag "Margins" margin) (const :tag "Indicator at end-of-line" nil)) :version "31.1") (defcustom hs-indicator-maximum-buffer-size 2000000 ;2mb "Max buffer size in bytes where the indicators should be enabled. If current buffer is larger than this variable value, the indicators will be disabled. If set to nil, the indicators will be activated regardless of the buffer size." :type '(choice natnum (const :tag "No limit" nil)) :version "31.1") (define-fringe-bitmap 'hs-hide [#b0000000 #b1000001 #b1100011 #b0110110 #b0011100 #b0001000 #b0000000]) (define-fringe-bitmap 'hs-show [#b0110000 #b0011000 #b0001100 #b0000110 #b0001100 #b0011000 #b0110000]) (define-icon hs-indicator-hide nil `((image "outline-open.svg" "outline-open.pbm" :face hs-indicator-hide :height (0.6 . em) :ascent center) (symbol "▾" "▼" :face hs-indicator-hide) (text "-" :face hs-indicator-hide)) "Icon used for hide block at point. This is only used if `hs-indicator-type' is set to `margin' or nil." :version "31.1") (define-icon hs-indicator-show nil `((image "outline-close.svg" "outline-close.pbm" :face hs-indicator-show :height (0.6 . em) :ascent center) (symbol "▸" "▶" :face hs-indicator-show) (text "+" :face hs-indicator-show)) "Icon used for show block at point. This is only used if `hs-indicator-type' is set to `margin' or nil." :version "31.1") ;;;###autoload (defvar hs-special-modes-alist ;; FIXME: Currently the check is made via ;; (assoc major-mode hs-special-modes-alist) so it doesn't pay attention ;; to the mode hierarchy. '((c-mode "{" "}" "/[*/]" nil nil) (c-ts-mode "{" "}" "/[*/]" nil nil) (c++-mode "{" "}" "/[*/]" nil nil) (c++-ts-mode "{" "}" "/[*/]" nil nil) (bibtex-mode ("@\\S(*\\(\\s(\\)" 1)) (java-mode "{" "}" "/[*/]" nil nil) (java-ts-mode "{" "}" "/[*/]" nil nil) (js-mode "{" "}" "/[*/]" nil) (js-ts-mode "{" "}" "/[*/]" nil) (mhtml-mode "{\\|<[^/>]*?" "}\\|]*[^/]>" "