ELPA Logo NonGNU-devel ELPA: treesit-fold

treesit-fold Atom Feed

Description
Code folding using treesit
Latest
treesit-fold.tar (.sig), 2026-Jun-19, 1.27 MiB
Maintainer
Shen, Jen-Chieh <jcs090218@gmail.com>
Other versions:
release version
Website
https://github.com/emacs-tree-sitter/treesit-fold
ELPA's Repository
CGit or Gitweb
Badge

To install this package from Emacs, use package-install or list-packages.

Full description

[!IMPORTANT]

This package is code folding support for built-in treesit.el (since Emacs 29.1).

For external tree-sitter.el (support Emacs 26.1+), please use ts-fold instead.

License: GPL v3 NonGNU ELPA JCS-ELPA

treesit-fold

Code-folding using treesit

CI

treesit-fold builds on top of treesit.el to provide code folding based on the tree-sitter syntax tree.

Table of Contents

💾 Installation

🔍 Method 1. with straight.el and use-package:
(use-package treesit-fold
  :straight (treesit-fold :type git :host github :repo "emacs-tree-sitter/treesit-fold"))
🔍 Method 2. Manual
git clone https://github.com/emacs-tree-sitter/treesit-fold /path/to/lib

then in Emacs:

(add-to-list 'load-path "/path/to/lib")
(require treesit-fold)

or

(use-package treesit-fold
  :load-path "/path/to/lib")

🖥 Usage

📇 Commands

The following are the functions provided by treesit-fold-mode

Commands for enabling treesit-fold:

Commands Description
treesit-fold-mode enable treesit-fold-mode in the current buffer.
global-treesit-fold-mode enable treesit-fold-mode whenever tree-sitter is turned on and the major mode is supported by treesit-fold.
treesit-fold-indicators-mode enable treesit-fold with indicators in the current buffer. See plugins section.
global-treesit-fold-indicators-mode enable treesit-fold with indicators globally. See plugins section.
treesit-fold-line-comment-mode enable line comment folding.

Commands for using treesit-fold.

Commands Description
treesit-fold-close fold the current syntax node.
treesit-fold-open open the outermost fold of the current syntax node. Keep the sub-folds close.
treesit-fold-open-recursively open all folds inside the current syntax node.
treesit-fold-close-all close all foldable syntax nodes in the current buffer.
treesit-fold-open-all open all folded syntax nodes in the current buffer.
treesit-fold-toggle toggle the syntax node at `point'.

If evil mode is loaded, then these commands are also added to the evil folding list.

🔨 Supported languages

⚠️ Please sort these two lists alphabetically!

These languages are fairly complete:

These languages are in development:

P.S. We don't list trivial languages here. e.g., LLVM IR (.ll) files, etc. Please see the variable treesit-fold-range-alist for the fully supported list!

📝 Customization

Although treesit-fold aims to have good folding out of the box for all supported definitions, people will indubitably have their own preferences or desired functionality. The following section outlines how to add your own folding definitions and folding functions to make treesit-fold work for you. If there are any improvements you find for existing or new languages, please do raise a PR so that others may benefit from better folding in the future!

⚪ Folding on new nodes

Treesit-fold defines all its folding definitions in the variable treesit-fold-range-alist which is an alist with the key of the alist being the mode and the value being another alist of fold definitions.

;; Example of treesit-fold-range-alist's structure
'((c-mode     . c-folding-definitions) ;; <language>-folding-definitions is structured as shown below
  (css-mode   . css-folding-definitions)
  (go-mode    . go-folding-definitions)
  (scala-mode . scala-folding-definitions)
  ...)

;; Examle of a folding definition alist
(setq css-folding-definitions
    (block   . treesit-fold-range-seq)
    (comment . treesit-fold-range-c-like-comment))

So you can select whatever node that you want to fold on it.

To find what node you'll want to fold closed, refer to the Emacs tree-sitter documentation about viewing nodes. treesit-inspect-mode and treesit-explore-mode are both very useful for this.

For the folding functions, treesit-fold provides some default

- `treesit-fold-range-markers` - Folds the node starting from a giving delimiter character. Useful if tree-sitter's node definition doesn't align with the start of the desired folding section. **NOTE:** This folding function requires a lambda (or an externally defined function wrapper) so that the delimiter can be specified. You usually don't need to worry about the `node` and `offset` variables, so just pass them through.
type Dog interface {
    Bark() (string, error)
    Beg() (bool, error)
}

/* | Note: The tree-sitter node starts at the word interface, not at the '{'.
 * | '(interface_type . (lambda (node offset)
 * |                      (treesit-fold-range-markers node offset "{" "}")))
 * V
 */

type Dog interface {...}

Now that you know what kinds of folds are easily available in treesit-fold, you can go ahead and add new fold definitions to `treesit-fold-range-alist` and be good to go!
❔ Example
Let's look at a quick example of adding a new folding definition. Let's say you want to add folding to `go-mode`'s `field_declaration_list`. The folding definition that is needed will be `'(field_declaration_list . treesit-fold-range-seq)`. To add this to the `treesit-fold-range-alist`, you can do something like the following.
(push '(field_declaration_list . treesit-fold-range-seq) (alist-get 'go-mode treesit-fold-range-alist))
Now the new fold definition should be usable by treesit-fold!
↔ Offset
With the functions listed above you'll be able to define most folding behavior that you'll want for most languages. However, sometimes you'll have a language where the delimiter is a word instead of a single character bracket and you want to offset your fold by a certain amount to accommodate it. That's where offsets come in. When adding a fold definition to a a language's fold alist, you can either provide the folding function directly as you've seen so far:
'(block . treesit-fold-range-seq)
Or you can provide the folding function with an offset:
'(block . (treesit-fold-range-seq 1 -3))
When a range is provided, it provides extra room on the ends of a fold. The way this works is most easily shown using an example. Lets say we want to write a fold for bash's `for...do...done` construct to look something like this:
for i in 1 2 3 4 5
do
   echo "Welcome $i times"
done

# |
# | '(do_group . <some folding function>)
# V

for i in 1 2 3 4 5
do...done
The `do...done` block is represented in tree-sitter as the node named `do_group`. However, if we just use `'(do_group . treesit-fold-range-seq)`, then we'll get results like the following:
for i in 1 2 3 4 5
d...e
which is hard to read. Instead, we can use the definition `'(do_group . (treesit-fold-range-seq 1 -3))` to offset the fold a bit to get our desired result!
🔍 Writing new fold functions
If the built in functions don't fit your needs, you can write your own fold parser! Folding functions take two parameters: Then the function needs to return a position range for the fold overlay in the form `'(start-of-fold . end-of-fold)`. If `nil` is returned instead of a range, then no fold is created. This can be useful if you want to add extra conditional logic onto your fold. As an example of a folding function, take a look at the definition of the basic `treesit-fold-range-seq`.
(defun treesit-fold-range-seq (node offset)
  "..."
  (let ((beg (1+ (treesit-node-start node)))  ; node beginning position
        (end (1- (treesit-node-end node))))   ; node end position
    (treesit-fold--cons-add (cons beg end) offset)))    ; return fold range
🔢 Line Count Display
The following variables let you toggle and customize the display of the line count for folded regions.

🔌 Plugins

treesit-fold comes with a couple of useful little additions that can be used or turned off as desired.
⚖ Indicators Mode

This plugin adds interactive visual markers in the gutter that show where folds can be made. They can be clicked on to fold or unfold given nodes.
💾 Installation
`treesit-fold-indicator-mode` is loaded when `treesit-fold-mode` is and the functionality should be auto-loaded in, however if that's not working then you may want to explicitly declare the package in in your config.
🖥 Usage
You can then enable this manually by doing either of the following:
M-x treesit-fold-indicators-mode

M-x global-treesit-fold-indicators-mode
Please note that turning on `treesit-fold-indicators-mode` automatically turns on `treesit-fold-mode` as well. Though, turning off `treesit-fold-indicators-mode` does not turn off `treesit-fold-mode`
📝 Summary

This plugin automatically extracts summary from the comment/document string, so you can have a nice way to peek at what's inside the fold range.
🖥 Usage
📝 Customization
Just like with fold definitions, you can create your own summary definitions. Summary definitions are defined in `treesit-fold-summary-parsers-alist` and has one summary function per major mode `'(java-mode . fold-summary-function)`. The summary function takes in the doc string which is all the text from a doc node and then returns a string to be displayed in its stead. Unlike with the folding functions, there aren't a set of general summary functions to fall back on. However, there are lots of examples and helper functions present in `treesit-fold-summary.el`. Let's look at one example here.
(defun treesit-fold-summary-javadoc (doc-str)
  "Extract summary from DOC-STR in Javadoc."
  (treesit-fold-summary--generic doc-str "*")) ;; strip the '*' and returns the first line
As can be seen `treesit-fold-summary--generic` is a very helpful function since it removes the provided delimiter and returns the first line. often this will be enough.
🌫 Line-Comment folding

This plugin makes line comment into foldable range.
🖥 Usage
M-x treesit-fold-line-comment-mode

❓ FAQ

💫 Adding support for derived modes

You can add support for derived modes where the parent mode has existing support. For example, a new mode which derives from YAML would be added to the support list like this:

(push `(<your-major>-mode . ,(treesit-fold-parsers-yaml)) treesit-fold-range-alist)
💫 Add support for non-ts modes

You can add folding support for non-ts modes (such as c-mode or emacs-lisp-mode), this requires you have the parser library for the mode. After, you can enable folding adding these code snippets to your configuration:

;; For `treesit-parser-create' you need to ensure the language fits with
;; the parser library (e.g `libtree-sitter-cpp.dll' is 'cpp).

(add-hook 'emacs-lisp-mode-hook (lambda () (treesit-parser-create 'elisp)))

;; For use-package users
(use-package treesit-fold
  :hook (c-mode . (lambda () (treesit-parser-create 'c)))
  ...)

🔰 Contribute

PRs Welcome Elisp styleguide Donate on paypal Become a patron

Ensure your buffer has a tree-sitter parser first, then treesit-explore-mode is useful to test out queries that determine what syntax nodes should be foldable and how to fold them. Emacs repository and Emacs tree-sitter manual has an excellent documentation on how to write tree-sitter queries.

🔬 Development

To run the test locally, you will need the following tools:

Install all dependencies and development dependencies:

eask install-deps --dev

To test the package's installation:

eask package
eask install

To test compilation:

eask compile

🪧 The following steps are optional, but we recommend you follow these lint results!

The built-in checkdoc linter:

eask lint checkdoc

The standard package linter:

eask lint package

📝 P.S. For more information, find the Eask manual at https://emacs-eask.github.io/.

❓ How to add a folding parser?

When adding a new folding parser, add the folding definition function to treesit-fold.el itself near where the other range functions live and then add the parser to treesit-fold-parsers.el file. Finally, if you are adding support for a new language, remember to add it to the treesit-fold-range-alist variable.

When creating a new parser, name it treesit-fold-parsers-<language>.

When creating a new folding function, name it treesit-fold-range-<language>-<feature> or something similar.

🔍 Where can I look for tree-sitter node?

Here are some techniques for finding your desired nodes in tree-sitter.

To look for the correct node you have three options:

[!WARNING]

Make sure you look into the correct repository. Some repositories are managed under https://github.com/tree-sitter/[lang].

❓ How to create a summary parser?

treesit-fold-summary.el module is used to extract and display a short description from the comment/docstring.

To create a summary parser, you just have to create a function that could extract comment syntax correctly then register this function to treesit-fold-summary-parsers-alist defined in treesit-fold-summary.el. The display and shortening will be handled by the module itself.

Functions should be named with the prefix treesit-fold-summary- followed by style name. For example, to create a summary parser for Javadoc style, then it should be named treesit-fold-summary-javadoc.

⚜️ License

This program 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.

This program 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 this program. If not, see https://www.gnu.org/licenses/.

See LICENSE for details.

Old versions

treesit-fold-0.2.1.0.20260619.51.tar.lz2026-Jun-191019 KiB
treesit-fold-0.2.1.0.20260619.51.tar2026-Jun-191.27 MiB
treesit-fold-0.2.1.0.20260417.100827.tar.lz2026-Apr-171019 KiB
treesit-fold-0.2.1.0.20260226.70748.tar.lz2026-Feb-261019 KiB
treesit-fold-0.2.1.0.20260117.211549.tar.lz2026-Jan-181019 KiB
treesit-fold-0.2.1.0.20260117.80015.tar.lz2026-Jan-171019 KiB
treesit-fold-0.2.1.0.20260113.192122.tar.lz2026-Jan-141019 KiB
treesit-fold-0.2.1.0.20251231.162628.tar.lz2025-Dec-311018 KiB
treesit-fold-0.2.1.0.20251121.62118.tar.lz2025-Nov-221018 KiB
treesit-fold-0.2.1.0.20250911.3703.tar.lz2025-Sep-111018 KiB
treesit-fold-0.1.0.0.20250212.114521.tar.lz2025-Feb-121017 KiB
treesit-fold-0.1.0.0.20240630.204821.tar.lz2024-Jul-01 946 KiB

News

Change Log

All notable changes to this project will be documented in this file.

Check Keep a Changelog for recommendations on how to structure this file.

0.3.0 (Unreleased)

Released N/A

0.2.0

Released Feb 12, 2025

0.1.0

Released Jun 22, 2024