Skip to content

gggion/lisp-docstring-toggle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 

Repository files navigation

lisp-docstring-toggle: Toggle visibility of Lisp docstrings

MELPA

Important

Now on MELPA

lisp-docstring-toggle provides commands to hide and show Lisp docstrings in code buffers. It solves a specific problem: while comprehensive inline documentation aids code understanding, it creates visual clutter during code review, refactoring, or study, forcing the reader to scroll through multiple screens to view a few hundred lines of actual code.

Unlike general code folding tools (such as outline-mode or hideshow) that hide entire forms, lisp-docstring-toggle targets only docstrings. Function signatures, argument lists, and implementation bodies remain visible.

The package operates through Emacs overlays, which hide text without modifying buffer content. This integrates cleanly with custom font-lock rules (like hl-todo), undo/redo, and other Emacs text properties.

Screenshots

https://github.com/gggion/lisp-docstring-toggle/blob/screenshots/test.gif?raw=true

Quick Start

For Emacs Lisp and Common Lisp

Add to your configuration:

(add-hook 'emacs-lisp-mode-hook #'lisp-docstring-toggle-setup)
(add-hook 'lisp-mode-hook #'lisp-docstring-toggle-setup)

For Scheme, Clojure, Fennel, or other Lisp modes, enable the minor mode directly:

(add-hook 'scheme-mode-hook #'lisp-docstring-toggle-mode)
(add-hook 'clojure-mode-hook #'lisp-docstring-toggle-mode)

Manual Activation

In any buffer, run M-x lisp-docstring-toggle-mode to enable the minor mode.

Default Keybindings

With the minor mode enabled:

C-c , tToggle all docstrings in buffer
C-c , .Toggle docstring at point
C-c , DShow debug information

The prefix C-c , can be customized (see Customization section below).

Installation

From MELPA (NEW!)

(use-package lisp-docstring-toggle
  :ensure t
  :hook
  ;; For Emacs Lisp and Common Lisp
  ((emacs-lisp-mode lisp-mode) . lisp-docstring-toggle-setup)
  ;; For other Lisp dialects, use the mode directly
  ((scheme-mode clojure-mode clojure-ts-mode fennel-mode) . lisp-docstring-toggle-mode)

Default keybindings: C-c , t, C-c , ., C-c , D

From source

Clone the repository:

git clone https://github.com/gggion/lisp-docstring-toggle.git ~/.emacs.d/lisp/lisp-docstring-toggle

Add to your configuration:

(add-to-list 'load-path "~/.emacs.d/lisp/lisp-docstring-toggle")
(require 'lisp-docstring-toggle)

;; For Emacs Lisp, Common Lisp and other lisp-mode derived modes
(add-hook 'emacs-lisp-mode-hook #'lisp-docstring-toggle-setup)
(add-hook 'lisp-mode-hook #'lisp-docstring-toggle-setup)

;; For other Lisp dialects, use the mode directly
(add-hook 'scheme-mode-hook #'lisp-docstring-toggle-mode)
(add-hook 'clojure-mode-hook #'lisp-docstring-toggle-mode)

;; or if you're using treesitter modes
(add-hook 'clojure-ts-mode-hook #'lisp-docstring-toggle-mode)

Default keybindings: C-c , t, C-c , ., C-c , D

With use-package

(use-package lisp-docstring-toggle
  :ensure t
  :hook
  ;; For Emacs Lisp, Common Lisp and other lisp-mode derived modes
  ((emacs-lisp-mode lisp-mode) . lisp-docstring-toggle-setup)

  ;; For other Lisp dialects, use the mode directly
  ((scheme-mode clojure-mode clojure-ts-mode fennel-mode) . lisp-docstring-toggle-mode)

Doom Emacs

In packages.el:

(package! lisp-docstring-toggle)

In config.el:

(use-package! lisp-docstring-toggle
  :hook
  ;; For Emacs Lisp, Common Lisp and other lisp-mode derived modes
  ((emacs-lisp-mode lisp-mode) . lisp-docstring-toggle-setup)

  ;; For other Lisp dialects, use the mode directly
  ((scheme-mode clojure-ts-mode fennel-mode) . lisp-docstring-toggle-mode))

With straight.el

(straight-use-package
 '(lisp-docstring-toggle :type git :host github
                         :repo "gggion/lisp-docstring-toggle"))

Usage

Commands

Toggle all docstrings

The primary command is lisp-docstring-toggle (bound to C-c , t), which toggles visibility of all docstrings in the buffer.

When docstrings are visible:

(defun example-function-1 (arg)
  "This is a comprehensive docstring explaining
  the function's purpose, arguments, and return value.

  ARG is the input argument.

  Returns the result of computation."
  (+ arg 1))

(defun example-function-2 (arg)
  "This is another comprehensive docstring explaining
  the function's purpose, arguments, and return value.

  ARG is the input argument.

  Returns the result of computation."
  (+ arg 2))

After invoking lisp-docstring-toggle:

(defun example-function-1 (arg)
  "[…]"
  (+ arg 1))

(defun example-function-2 (arg)
  "[…]"
  (+ arg 2))

The function signature and body remain visible. Only the docstring is hidden.

Toggle docstring at point

Use lisp-docstring-toggle-at-point (C-c , .) to toggle only the docstring in the current form.

This is useful for selectively hiding verbose docstrings while keeping others visible. Point can be:

  • At the opening parenthesis of a form
  • Anywhere inside a form
  • On the defun, defvar, or other definition keyword

If point is outside any form, the command displays an error message.

Debug docstring detection

The command lisp-docstring-toggle-debug-show-snippets (C-c , D) opens a buffer showing all detected docstrings with:

  • Clickable position links for navigation
  • Character counts
  • First and last two lines of content

This is useful for:

  • Verifying that docstrings are detected correctly
  • Navigating to specific docstrings
  • Troubleshooting detection issues with mixed fontification

Customization

Keybinding Prefix

The user option lisp-docstring-toggle-keymap-prefix controls the prefix key for all commands. The default is C-c , which follows Emacs minor mode conventions (C-c followed by a punctuation character).

If you prefer a different prefix, customize this variable:

;; Use C-c C-d if it doesn't conflict with your major modes
(setq lisp-docstring-toggle-keymap-prefix "C-c C-d")

;; Or use another punctuation character
(setq lisp-docstring-toggle-keymap-prefix "C-c '")

After changing this variable, restart lisp-docstring-toggle-mode for the change to take effect.

Hiding styles

The user option lisp-docstring-toggle-hide-style controls how docstrings are hidden. It accepts three values:

Complete hiding

Setting the value to 'complete (the default) hides all docstring content:

(setq lisp-docstring-toggle-hide-style 'complete)

Result:

(defun example ()
  "[…]"
  (body))

Only the ellipsis indicator is visible.

Partial visibility

Setting the value to 'partial shows the first N characters:

(setq lisp-docstring-toggle-hide-style 'partial
      lisp-docstring-toggle-partial-chars 40)

Result:

(defun example ()
  "This is a comprehensive docstring ex[…]"
  (body))

The opening quote, first 40 characters, and closing quote remain visible.

This style provides context about the docstring’s content while reducing visual clutter.

First line only

Setting the value to 'first-line shows only the first line:

(setq lisp-docstring-toggle-hide-style 'first-line)

Result:

(defun example ()
  "This is a comprehensive docstring
  […]"
  (body))

This is useful for docstrings that follow the Emacs convention of placing a summary on the first line.

Customizing the ellipsis

The user option lisp-docstring-toggle-ellipsis controls the indicator shown for hidden docstrings.

Default value:

(setq lisp-docstring-toggle-ellipsis "[…]")

Alternative indicators:

;; Subtle Unicode ellipsis
(setq lisp-docstring-toggle-ellipsis "")

;; ASCII alternative
(setq lisp-docstring-toggle-ellipsis "...")

;; Descriptive indicator
(setq lisp-docstring-toggle-ellipsis " [hidden]")

;; No indicator
(setq lisp-docstring-toggle-ellipsis nil)

Setting the value to nil hides docstrings without any visual indicator.

Complete configuration example

(use-package lisp-docstring-toggle
  :ensure t
  :hook ((emacs-lisp-mode lisp-mode) . lisp-docstring-toggle-setup)
  :custom
  ;; Use C-c C-d prefix if it doesn't conflict
  (lisp-docstring-toggle-keymap-prefix "C-c C-d")
  ;; Show first 20 characters of docstrings when hiding
  (lisp-docstring-toggle-hide-style 'partial)
  (lisp-docstring-toggle-partial-chars 20)
  ;; Use a subtle ellipsis indicator
  (lisp-docstring-toggle-ellipsis ""))

Compatibility

Supported major modes

The package works with any major mode that:

  1. Uses font-lock-doc-face for docstring highlighting
  2. Supports beginning-of-defun and end-of-defun navigation
  3. Uses string literals (enclosed in quotes) for docstrings

Tested and working in Emacs 29.1+ with:

  • emacs-lisp-mode (built-in)
  • lisp-mode (built-in)
  • scheme-mode (built-in)
  • clojure-mode (MELPA package)
  • fennel-mode (MELPA package)
  • hy-mode (MELPA package)

Other Lisp modes should work if they use font-lock-doc-face.

The package does not work with:

  • Python (python-mode uses triple-quoted strings with different conventions)
  • Rust (documentation comments use /// syntax)
  • C/C++ (Doxygen comments are not string literals)
  • Other non-Lisp languages

Interaction with other packages

hl-todo

The package handles mixed fontification from hl-todo correctly. Keywords like TODO, FIXME, and NOTE within docstrings are detected properly:

(defun example ()
  "This function needs work. TODO: Optimize this."
  ;;                             ^^^^
  ;;                    Different face from hl-todo
  (body))

The detection algorithm finds the complete docstring despite face splits.

outline-mode and hideshow

You can use lisp-docstring-toggle alongside outline-mode or hideshow for different folding levels:

  • Use hideshow to fold function bodies
  • Use lisp-docstring-toggle to fold docstrings within visible functions

The two mechanisms operate independently because they use different overlay properties and invisibility specs. You can combine them for multi-level folding.

Setup Function vs. Minor Mode

The package provides two initialization mechanisms:
  • lisp-docstring-toggle-setup: Checks if the current mode is derived from lisp-mode or emacs-lisp-mode before enabling the minor mode. Use this for Emacs Lisp and Common Lisp buffers.
  • lisp-docstring-toggle-mode: Enables the minor mode unconditionally. Use this for Scheme, Clojure, Fennel, or any other Lisp dialect that uses font-lock-doc-face for docstrings.

Both approaches provide the same functionality. The setup function exists to prevent accidental activation in non-Lisp buffers when added to global hooks.

Technical details

Detection algorithm

The docstring detection algorithm operates in stages:

  1. Font-lock identification: Scan for characters with font-lock-doc-face
  2. Form boundary detection: Use beginning-of-defun and end-of-defun to locate the containing form
  3. String literal parsing: Search backward for the opening quote, forward for the closing quote
  4. Escape handling: Count consecutive backslashes before each quote. An even count (including zero) means the quote is unescaped and terminates the string. An odd count means the quote is escaped and is part of the string content.
  5. Validation: Ensure the detected region is actually a string literal

This multi-stage approach handles:

  • Mixed fontification (for example, hl-todo highlighting within docstrings)
  • Escaped quotes within docstrings
  • Malformed or incomplete forms
  • Nested string literals

Overlay properties

Overlays created by this package have these properties:

  • invisible: Set to 'lisp-docstring-toggle for invisibility control
  • lisp-docstring-toggle: Set to t for overlay identification
  • evaporate: Set to t for automatic cleanup when text is deleted
  • after-string: Contains the ellipsis indicator (if configured)

The invisible property works through Emacs’s invisibility specification system. Adding 'lisp-docstring-toggle to buffer-invisibility-spec activates hiding. Removing it reveals all hidden text.

See also: (Elisp Manual) Overlay Properties

Limitations

lisp-docstring-toggle does not:

  • Fold code blocks or function bodies (use hideshow or outline-mode)
  • Work with non-Lisp languages (detection relies on Lisp-specific conventions)
  • Detect docstrings in all nested forms (requires more testing)
  • Modify buffer content (operates purely through display properties)
  • Provide project-wide docstring management (operates per-buffer)

For general code folding, consider outline-mode, hideshow, or origami.el. For documentation generation, see tools like eldoc, helpful, or language-specific documentation systems.

Troubleshooting

Minor mode not activating in Scheme/Clojure/other Lisp modes

If you’re using lisp-docstring-toggle-setup but the mode doesn’t activate:
  1. Check if your major mode is derived from lisp-mode or emacs-lisp-mode:
    ;; eval this in your lisp buffer
    (derived-mode-p 'lisp-mode 'emacs-lisp-mode)
    ;; => t (in Emacs Lisp or Common Lisp buffers)
    ;; => nil (in Scheme, Clojure, or other Lisp buffers)
        
  2. If this returns nil, use lisp-docstring-toggle-mode directly instead:
    (add-hook 'scheme-mode-hook #'lisp-docstring-toggle-mode)
        
  3. Verify docstrings use font-lock-doc-face: Place cursor on a docstring and run M-x describe-char, there in the text properties you should find: face: font-lock-doc-face

Docstrings not detected

If docstrings are not being hidden:

  1. Verify font-lock is active: M-x font-lock-mode should show “enabled”
  2. Check if docstrings use font-lock-doc-face: Place cursor on a docstring and run M-x describe-char
  3. Run M-x lisp-docstring-toggle-debug-show-snippets to see what is detected

Performance issues

On very large files (more than 100k lines), initial detection may be slow due to font-lock-ensure. This is a one-time cost per toggle operation.

Conflicts with other packages

If you experience issues with other packages:

  1. Disable other folding packages temporarily
  2. Check for conflicting keybindings with M-x describe-key
  3. Report the issue at https://github.com/gggion/lisp-docstring-toggle/issues

Contributing

Bug reports and feature requests are welcome at: https://github.com/gggion/lisp-docstring-toggle/issues

When reporting bugs, please include:

  • Emacs version (M-x emacs-version)
  • Major mode where the issue occurs
  • Minimal reproduction steps
  • Output of M-x lisp-docstring-toggle-debug-show-snippets

Pull requests should:

  • Include tests for new functionality
  • Follow existing code style
  • Update documentation as needed

Acknowledgments

This package was inspired by:

  • hideif.el: Overlay management patterns
  • pel-hide-docstring.el: Partial visibility concept
  • font-lock.el and lisp-mode.el: Docstring detection conventions

Thanks to:

License

GPLv3

About

Docstring visibility control for Lisp code

Resources

License

Stars

Watchers

Forks

Packages

No packages published