outline-indent.el – Indentation based Folding and Outlining in Emacs

The outline-indent.el Emacs package provides a minor mode that enables code folding and outlining based on indentation levels for various indentation-based text files, such as YAML, Python, and other indented text files.

In addition to code folding, outline-indent.el allows moving indented sub-trees up and down, promoting and demoting sections to adjust indentation levels, customizing the ellipsis, and inserting a new line with the same indentation level as the current line, among other features.

The outline-indent.el package leverages the built-in outline-minor-mode, which is maintained by the Emacs developers and has less chance of being abandoned like origami.el.

The outline-indent.el Emacs package offers a similar functionality to Vim’s set foldmethod=indent setting. Just as in Vim, it allows to fold and unfold code sections based on their indentation levels.

Installation

To install the outline-indent from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.
  2. Add the following code to your Emacs init file to install the outline-indent package from MELPA:
(use-package outline-indent
  :ensure t
  :custom
  (outline-indent-ellipsis " ▼ "))Code language: Lisp (lisp)

Usage

Once installed, the minor mode can be activated using:

(outline-indent-minor-mode)Code language: Lisp (lisp)

The minor mode can also be automatically activated for a certain mode. For example for Python and YAML:

(add-hook 'python-mode-hook #'outline-indent-minor-mode)
(add-hook 'python-ts-mode-hook #'outline-indent-minor-mode)

(add-hook 'yaml-mode-hook #'outline-indent-minor-mode)
(add-hook 'yaml-ts-mode-hook #'outline-indent-minor-mode)Code language: Lisp (lisp)

(You can also adjust the indentation offset by modifying the variable outline-indent-default-offset)

Once outline-indent-minor-mode is activated, you can use the built-in outline-minor-mode functions to fold or unfold indented sections:

  • outline-hide-body: Hide all body lines in buffer, leaving all headings visible.
  • outline-hide-other: Hide everything except current body and parent and top-level headings.
  • outline-hide-entry: Hide the body directly following this heading.
  • outline-hide-leaves: Hide the body after this heading and at deeper levels.
  • outline-hide-subtree: Hide everything after this heading at deeper levels.
  • outline-show-children: Show all direct subheadings of this heading.
  • outline-hide-sublevels: Hide everything but the top LEVELS levels of headers, in whole buffer.
  • outline-show-all: Show all of the text in the buffer.
  • outline-show-entry: Show the body directly following this heading.
  • outline-show-subtree: Show everything after this heading at deeper levels.
  • outline-show-branches: Show all subheadings of this heading, but not their bodies.
  • outline-show-children: Show all direct subheadings of this heading.

You can also indent/unindent and move subtree up and down:

  • (outline-indent-demote) and (outline-indent-promote): Indent or unindent the entire subtree.
  • (outline-indent-move-subtree-down) and (outline-indent-move-subtree-up) to move the current subtree up or down.
  • (outline-insert-heading) to insert a new line with the same indentation level/depth as the current line just before the next heading that shares the same or less indentation level.

In Evil mode, outline-indent-minor-mode works out of the box, and you can use the Evil keyboard mappings: zo, zc, zO, zC, za, zr, and zm to manage folds.

Related links

Emacs: Enhancing up and down subtree movement in outline-mode and outline-minor-mode

When editing outlined files (e.g., using the built-in outline-minor-mode, or packages like outline-indent.el, outline-yaml.el, etc.), handling subtrees efficiently can significantly enhance productivity, especially when working with complex documents. If you’re familiar with outline-mode or outline-minor-mode, you might have noticed that the built-in functions for moving subtrees up and down, outline-move-subtree-up and outline-move-subtree-down:

  • Blank line exclusion: outline-move-subtree-up and outline-move-subtree-down exclude the last blank line of the subtree when the outline-blank-line variable is set to t. Setting outline-blank-line to t is worthwhile because it retains a visible blank line after the subtree and before the next heading, improving the readability of the document.
  • Cursor position reset: After moving a subtree up or down, the cursor position is often reset, which can be disruptive during editing.

Here’s how you can address these issues by using custom functions to enhance subtree movement:

(require 'outline)

(defun my-advice-outline-hide-subtree (orig-fun &rest args)
  "Advice for `outline-hide-subtree'.
This ensures that the outline is folded correctly by
outline-move-subtree-up/down, preventing it from being unable to open the fold."
  (let ((outline-blank-line
         (if (bound-and-true-p my-outline-hide-subtree-blank-line-enabled)
             my-outline-hide-subtree-blank-line
           outline-blank-line)))
    (apply orig-fun args)))

(defun my-advice-outline-move-subtree-up-down (orig-fun &rest args)
  "Move the current subtree up/down past ARGS headlines of the same level.
This function ensures the last blank line is included, even when
`outline-blank-line' is set to t. It also restores the cursor position,
addressing the issue where the cursor might be reset after the operation."
  (interactive "p")
  (let ((column (current-column))
        (outline-blank-line nil)
        (my-outline-hide-subtree-blank-line-enabled t)
        (my-outline-hide-subtree-blank-line outline-blank-line))
    (apply orig-fun (or args 1))
    (move-to-column column)))

(advice-add 'outline-hide-subtree
            :around #'my-advice-outline-hide-subtree)
(advice-add 'outline-move-subtree-up
            :around #'my-advice-outline-move-subtree-up-down)
(advice-add 'outline-move-subtree-down
            :around #'my-advice-outline-move-subtree-up-down)Code language: Lisp (lisp)

I also recommend using Ctrl-Up and Ctrl-Down key bindings for moving subtrees up and down.

(define-key outline-mode-map (kbd "C-<up>") 'outline-move-subtree-up)
(define-key outline-mode-map (kbd "C-<down>") 'outline-move-subtree-down)

(defun my-setup-outline-minor-mode-keybindings ()
    "Set up keybindings for moving subtrees in `outline-minor-mode'."
  (define-key outline-minor-mode-map (kbd "C-<up>") 'outline-move-subtree-up)
  (define-key outline-minor-mode-map (kbd "C-<down>") 'outline-move-subtree-down))
(add-hook 'outline-minor-mode-hook 'my-setup-outline-minor-mode-keybindings) Code language: Lisp (lisp)

With this setup, you will ensure that every time you use outline-move-subtree-up or outline-move-subtree-down, the last blank line of the subtree is included and the cursor position is restored.

Emacs: YAML file code Folding and Outlining

Recommendation: I recommend you to try a similar package from the same author: outline-indent.el, which provides a minor mode for Emacs that enables code folding and outlining based on indentation levels for various indent-based text files such as YAML, Python, and others. In addition to code folding, it allows moving indented subtrees up/down, customizing the ellipsis, and inserting a heading that creates a new line with the same indentation level/depth as the current line, among other features.

Working with long and complex YAML files can be a daunting task. In such cases, code folding becomes an invaluable tool, allowing the collapse and expansion of sections of the file and enhancing readability and navigation. This makes it easier to focus on specific parts of the code without being overwhelmed by the entire document.

To address this need, I would like to introduce you to outline-yaml.el, a minor mode for Emacs that brings code folding and outlining capabilities to YAML files, making editing YAML files more efficient and enjoyable. Leveraging Emacs’ built-in outline-minor-mode, outline-yaml.el provides a structured and navigable view of YAML content, simplifying the editing of even the most difficult YAML files.

Installation of outline-yaml.el

  1. Install and configure yaml-mode or yaml-ts-mode.
  2. If you haven’t already done so, add the straight.el bootstrap code to your init file.
  3. After that, add the following code to your Emacs init file:
(use-package outline-yaml
  :ensure t
  :straight (outline-yaml
             :type git
             :host github
             :repo "jamescherti/outline-yaml.el")
  :hook
  ((yaml-mode . outline-yaml-minor-mode)
   (yaml-ts-mode . outline-yaml-minor-mode)))Code language: Lisp (lisp)

How to change the Ellipsis (…) to (▼)?

The code snippet in this article can be used to to change the Ellipsis to ▼.

Links