├── .dir-locals.el
├── .github
├── FUNDING.yml
├── dependabot.yml
└── workflows
│ └── test.yml
├── .gitignore
├── CHANGELOG.md
├── Eask
├── LICENSE
├── Makefile
├── README.md
├── _scripts
├── clean.bat
└── clean.sh
├── etc
├── indicators.png
├── line-comment.gif
├── line-count-custom.png
├── line-count-default.png
├── screenshot.png
└── summary.gif
├── treesit-fold-indicators.el
├── treesit-fold-parsers.el
├── treesit-fold-summary.el
├── treesit-fold-util.el
└── treesit-fold.el
/.dir-locals.el:
--------------------------------------------------------------------------------
1 | ;;; Directory Local Variables
2 | ;;; For more information see (info "(emacs) Directory Variables")
3 |
4 | ((markdown-mode . ((fill-column . 80)))
5 | (emacs-lisp-mode . ((indent-tabs-mode . nil))))
6 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [emacs-tree-sitter, jcs090218]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # replace with a single OpenCollective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: github-actions
4 | directory: /
5 | schedule:
6 | interval: daily
7 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | workflow_dispatch:
9 |
10 | concurrency:
11 | group: ${{ github.workflow }}-${{ github.ref }}
12 | cancel-in-progress: true
13 |
14 | jobs:
15 | test:
16 | runs-on: ${{ matrix.os }}
17 | continue-on-error: ${{ matrix.experimental }}
18 | strategy:
19 | fail-fast: false
20 | matrix:
21 | os: [ubuntu-latest, macos-latest, windows-latest]
22 | emacs-version:
23 | - 29.4
24 | - 30.1
25 | experimental: [false]
26 | include:
27 | - os: ubuntu-latest
28 | emacs-version: snapshot
29 | experimental: true
30 | - os: macos-latest
31 | emacs-version: snapshot
32 | experimental: true
33 | - os: windows-latest
34 | emacs-version: snapshot
35 | experimental: true
36 |
37 | steps:
38 | - uses: actions/checkout@v4
39 |
40 | - uses: jcs090218/setup-emacs@master
41 | with:
42 | version: ${{ matrix.emacs-version }}
43 |
44 | - uses: emacs-eask/setup-eask@master
45 | with:
46 | version: 'snapshot'
47 |
48 | - name: Run tests
49 | run:
50 | make ci
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ignore these directories
2 | /.git
3 | /recipes
4 | /_test
5 |
6 | # ignore generated files
7 | *.elc
8 |
9 | # eask packages
10 | .eask/
11 | dist/
12 |
13 | # packaging
14 | *-autoloads.el
15 | *-pkg.el
16 |
17 | # OS generated
18 | .DS_Store
19 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
6 |
7 |
8 | ## 0.3.0 (Unreleased)
9 | > Released N/A
10 |
11 | * feat(parsers): Improve folding of block nodes in python (#32)
12 | * feat: Add basic `Magik` support (76bba5243883f6c8bff51c744c31e287a045a9f5)
13 |
14 | ## 0.2.0
15 | > Released Feb 12, 2025
16 |
17 | * feat: Add `HEEx` support (#19)
18 | * feat: Add `EditorConfig` support (#20)
19 | * feat: Add `Janet` support (#22)
20 | * refactor: Use built-in ellipsis (#24)
21 | * feat: add line count to folded text overlay (#26)
22 |
23 | ## 0.1.0
24 | > Released Jun 22, 2024
25 |
26 | * feat: Fully support `isearch` and modification conditions (#1)
27 | * fix: Respect same line folding from close all (4ef65016fdfdc6d45567ac62bf25814b07a8cad7)
28 | * `treesit.el` support (#3)
29 | * Add `Gleam` support (#8)
30 |
--------------------------------------------------------------------------------
/Eask:
--------------------------------------------------------------------------------
1 | ;; -*- mode: eask; lexical-binding: t -*-
2 |
3 | (package "treesit-fold"
4 | "0.2.1"
5 | "Code folding using treesit")
6 |
7 | (website-url "https://github.com/emacs-tree-sitter/treesit-fold")
8 | (keywords "convenience" "folding" "tree-sitter")
9 |
10 | (package-file "treesit-fold.el")
11 | (files "treesit-*.el")
12 |
13 | (script "test" "echo \"Error: no test specified\" && exit 1")
14 |
15 | (source 'gnu)
16 | (source 'melpa)
17 |
18 | (depends-on "emacs" "29.1")
19 |
20 | (setq network-security-level 'low) ; see https://github.com/jcs090218/setup-emacs-windows/issues/156#issuecomment-932956432
21 |
22 | (add-hook 'eask-before-compile-hook
23 | (lambda ()
24 | (setq byte-compile-error-on-warn t)))
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | EMACS ?= emacs
2 | EASK ?= eask
3 |
4 | .PHONY: clean checkdoc lint package install compile test
5 |
6 | # XXX: The `lint` test is too aggresive, let's ignore it
7 | ci: clean package install compile test checkdoc
8 |
9 | package:
10 | @echo "Packaging..."
11 | $(EASK) package
12 |
13 | install:
14 | @echo "Installing..."
15 | $(EASK) install
16 |
17 | compile:
18 | @echo "Compiling..."
19 | $(EASK) compile
20 |
21 | test:
22 | @echo "Testing..."
23 | $(EASK) test ert ./test/*.el
24 |
25 | checkdoc:
26 | @echo "Run checkdoc..."
27 | $(EASK) lint checkdoc
28 |
29 | lint:
30 | @echo "Run package-lint..."
31 | $(EASK) lint package
32 |
33 | clean:
34 | $(EASK) clean all
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > [!IMPORTANT]
2 | >
3 | > This package is code folding support for built-in [treesit.el][] (**since Emacs 29.1**).
4 | >
5 | > For external [tree-sitter.el][] (**support Emacs 26.1+**), please use [ts-fold][] instead.
6 |
7 | [](https://www.gnu.org/licenses/gpl-3.0)
8 | [](https://elpa.nongnu.org/nongnu/treesit-fold.html)
9 | [](https://jcs-emacs.github.io/jcs-elpa/#/treesit-fold)
10 |
11 | # treesit-fold
12 |
13 | > Code-folding using treesit
14 |
15 | [](https://github.com/emacs-tree-sitter/treesit-fold/actions/workflows/test.yml)
16 |
17 | `treesit-fold` builds on top of `treesit.el` to provide code folding based on
18 | the tree-sitter syntax tree.
19 |
20 |
21 |
22 |
23 |
24 |
26 |
27 |
28 | **Table of Contents**
29 |
30 | - [💾 Installation](#-installation)
31 | - [🔍 Method 1. with `straight.el` and `use-package`:](#-method-1-with-straightel-and-use-package)
32 | - [🔍 Method 2. Manual](#-method-2-manual)
33 | - [🖥 Usage](#-usage)
34 | - [📇 Commands](#-commands)
35 | - [🔨 Supported languages](#-supported-languages)
36 | - [🚀 Add support for non-ts modes](#-add-support-for-non-ts-modes)
37 | - [📝 Customization](#-customization)
38 | - [⚪ Folding on new nodes](#-folding-on-new-nodes)
39 | - [❔ Example](#-example)
40 | - [↔ Offset](#-offset)
41 | - [🔍 Writing new fold functions](#-writing-new-fold-functions)
42 | - [🔢 Line Count Display](#-line-count-display)
43 | - [🔌 Plugins](#-plugins)
44 | - [⚖ Indicators Mode](#-indicators-mode)
45 | - [💾 Installation](#-installation-1)
46 | - [🖥 Usage](#-usage-1)
47 | - [📝 Summary](#-summary)
48 | - [🖥 Usage](#-usage-2)
49 | - [📝 Customization](#-customization-1)
50 | - [🌫 Line-Comment folding](#-line-comment-folding)
51 | - [🖥 Usage](#-usage-3)
52 | - [🔰 Contribute](#-contribute)
53 | - [🔬 Development](#-development)
54 | - [❓ How to add a folding parser?](#-how-to-add-a-folding-parser)
55 | - [🔍 Where can I look for tree-sitter node?](#-where-can-i-look-for-tree-sitter-node)
56 | - [❓ How to create a summary parser?](#-how-to-create-a-summary-parser)
57 | - [⚜️ License](#-license)
58 |
59 |
60 |
61 | ## 💾 Installation
62 |
63 | ### 🔍 Method 1. with `straight.el` and `use-package`:
64 |
65 | ```elisp
66 | (use-package treesit-fold
67 | :straight (treesit-fold :type git :host github :repo "emacs-tree-sitter/treesit-fold"))
68 | ```
69 |
70 | ### 🔍 Method 2. Manual
71 |
72 | ```sh
73 | git clone https://github.com/emacs-tree-sitter/treesit-fold /path/to/lib
74 | ```
75 |
76 | then in Emacs:
77 |
78 | ```elisp
79 | (add-to-list 'load-path "/path/to/lib")
80 | (require treesit-fold)
81 | ```
82 |
83 | or
84 |
85 | ```elisp
86 | (use-package treesit-fold
87 | :load-path "/path/to/lib")
88 | ```
89 |
90 | ## 🖥 Usage
91 |
92 | ### 📇 Commands
93 |
94 | The following are the functions provided by `treesit-fold-mode`
95 |
96 | Commands for enabling `treesit-fold`:
97 |
98 | | Commands | Description |
99 | |---------------------------------------|---------------------------------------------------------------------------------------------------------------|
100 | | `treesit-fold-mode` | enable `treesit-fold-mode` in the current buffer. |
101 | | `global-treesit-fold-mode` | enable `treesit-fold-mode` whenever tree-sitter is turned on and the major mode is supported by treesit-fold. |
102 | | `treesit-fold-indicators-mode` | enable `treesit-fold` with indicators in the current buffer. See [plugins section](#-indicators-mode). |
103 | | `global-treesit-fold-indicators-mode` | enable `treesit-fold` with indicators globally. See [plugins section](#-indicators-mode). |
104 | | `treesit-fold-line-comment-mode` | enable line comment folding. |
105 |
106 | Commands for using `treesit-fold`.
107 |
108 | | Commands | Description |
109 | |---------------------------------|-------------------------------------------------------------------------------|
110 | | `treesit-fold-close` | fold the current syntax node. |
111 | | `treesit-fold-open` | open the outermost fold of the current syntax node. Keep the sub-folds close. |
112 | | `treesit-fold-open-recursively` | open all folds inside the current syntax node. |
113 | | `treesit-fold-close-all` | close all foldable syntax nodes in the current buffer. |
114 | | `treesit-fold-open-all` | open all folded syntax nodes in the current buffer. |
115 | | `treesit-fold-toggle` | toggle the syntax node at `point'. |
116 |
117 | If evil mode is loaded, then these commands are also added to the evil folding list.
118 |
119 | ### 🔨 Supported languages
120 |
121 | > ⚠️ Please sort these two lists alphabetically!
122 |
123 | These languages are fairly complete:
124 |
125 | - ActionScript / Arduino / Assembly
126 | - Bash / Beancount
127 | - C / C++ / C# / Clojure / CMake / CSS
128 | - Dart
129 | - Elisp / Elixir / Erlang
130 | - Fish
131 | - GDScript / Gleam / GLSL / Go / Groovy (Jenkinsfile)
132 | - Haskell / Haxe / HEEx / HLSL / HTML
133 | - Jai / Janet / Java / JavaScript / JSX / JSON / Jsonnet / Julia
134 | - Kotlin
135 | - LaTex / Lisp / Lua
136 | - Make / MATLAB / Markdown / Mermaid
137 | - Ninja / Nix / Noir
138 | - OCaml / Org
139 | - Perl / PHP / Python
140 | - R / Ruby / Rust / reStructuredText
141 | - Scala / Scheme / SQL / Svelte / Swift
142 | - TOML / TypeScript / TSX
143 | - Verilog / VHDL / Vimscript
144 | - XML
145 | - YAML
146 | - Zig
147 |
148 | These languages are in development:
149 |
150 | - Ada
151 | - Agda
152 | - Elm
153 | - Fortran
154 | - Magik
155 | - Pascal
156 | - Smithy
157 |
158 | *P.S. We don't list trivial languages here. e.g., LLVM IR (`.ll`) files, etc.
159 | Please see the variable `treesit-fold-range-alist` for the fully supported list!*
160 |
161 | #### 🚀 Add support for non-ts modes
162 | You can add folding support for non-ts modes (such as c-mode or emacs-lisp-mode),
163 | this requires you have the parser library for the mode.
164 | After, you can enable folding adding these code snippets to your configuration:
165 |
166 | ``` elisp
167 | ;; For `treesit-parser-create' you need to ensure the language fits with
168 | ;; the parser library (e.g `libtree-sitter-cpp.dll' is 'cpp).
169 |
170 | (add-hook 'emacs-lisp-mode-hook (lambda () (treesit-parser-create 'elisp)))
171 |
172 | ;; For use-package users
173 | (use-package treesit-fold
174 | :hook (c-mode . (lambda () (treesit-parser-create 'c)))
175 | ...)
176 | ```
177 |
178 | ## 📝 Customization
179 |
180 | Although treesit-fold aims to have good folding out of the box for all supported
181 | definitions, people will indubitably have their own preferences or desired
182 | functionality. The following section outlines how to add your own folding
183 | definitions and folding functions to make treesit-fold work for you. If there are any
184 | improvements you find for existing or new languages, please do raise a PR so
185 | that others may benefit from better folding in the future!
186 |
187 | ### ⚪ Folding on new nodes
188 |
189 | Treesit-fold defines all its folding definitions in the variable
190 | `treesit-fold-range-alist` which is an alist with the key of the alist being the
191 | mode and the value being another alist of fold definitions.
192 |
193 | ```elisp
194 | ;; Example of treesit-fold-range-alist's structure
195 | '((c-mode . c-folding-definitions) ;; -folding-definitions is structured as shown below
196 | (css-mode . css-folding-definitions)
197 | (go-mode . go-folding-definitions)
198 | (scala-mode . scala-folding-definitions)
199 | ...)
200 |
201 | ;; Examle of a folding definition alist
202 | (setq css-folding-definitions
203 | (block . treesit-fold-range-seq)
204 | (comment . treesit-fold-range-c-like-comment))
205 | ```
206 |
207 | So you can select whatever node that you want to fold on it.
208 |
209 | To find what node you'll want to fold closed, refer to the
210 | [Emacs tree-sitter documentation](https://www.gnu.org/software/emacs/manual/html_node/elisp/Pattern-Matching.html)
211 | about viewing nodes. `treesit-inspect-mode` and `treesit-explore-mode`
212 | are both very useful for this.
213 |
214 | For the folding functions, treesit-fold provides some default
215 |
216 | - `treesit-fold-range-seq` - Folds from the start of the node to the end of the node
217 | leaving a buffer of one character on each side. Usually used for code blocks
218 | that have bracketing delimiters.
219 |
220 | ```c++
221 | int main() { // <-- start of tree-sitter block node
222 | printf("Hello, World\n");
223 | return 0;
224 | } // <-- end of tree-sitter block node
225 |
226 | // |
227 | // | '(block . treesit-fold-range-seq)
228 | // V
229 |
230 | int main() {...} // Folded node
231 | ```
232 |
233 | - `treesit-fold-range-markers` - Folds the node starting from a giving delimiter
234 | character. Useful if tree-sitter's node definition doesn't align with the
235 | start of the desired folding section.
236 |
237 | **NOTE:** This folding function requires a lambda (or an externally
238 | defined function wrapper) so that the delimiter can be specified. You
239 | usually don't need to worry about the `node` and `offset` variables, so just
240 | pass them through.
241 |
242 | ```go
243 | type Dog interface {
244 | Bark() (string, error)
245 | Beg() (bool, error)
246 | }
247 |
248 | /* | Note: The tree-sitter node starts at the word interface, not at the '{'.
249 | * | '(interface_type . (lambda (node offset)
250 | * | (treesit-fold-range-markers node offset "{" "}")))
251 | * V
252 | */
253 |
254 | type Dog interface {...}
255 | ```
256 |
257 | - `treesit-fold-range-block-comment` - Folds multi-line comments that are of the form
258 | `/*...*/`. Should show a summary if the commentary plugin is turned on.
259 |
260 | ```c++
261 | /*
262 | * The main function that gets run after program is compiled
263 | * Doesn't take any parameters
264 | */
265 | int main() {
266 | printf("Hello, World\n");
267 | return 0;
268 | }
269 |
270 | // |
271 | // | '(comment . treesit-fold-range-block-comment)
272 | // V
273 |
274 | /* The main function that gets run after program is compiled */
275 | int main() {
276 | printf("Hello, World\n");
277 | return 0;
278 | ```
279 |
280 | - `treesit-fold-range-line-comment` - For languages that have one line comment blocks
281 | with the comment delimiter starting each line. Condenses all the comment nodes
282 | into a single fold.
283 |
284 | **Note:** This folding function requires a lambda (or an externally
285 | defined function wrapper) so that the delimiter can be specified. You
286 | usually don't need to worry about the `node` and `offset` variables, so just
287 | pass them through.
288 |
289 | ```sh
290 | # show the long form of ls
291 | # and also display hidden files
292 | alias ll='ls -lah'
293 |
294 | # |
295 | # | (comment (lambda (node offset) (treesit-fold-range-line-comment node offset "#"))))
296 | # V
297 |
298 | # show the long form of ls...
299 | alias ll='ls -lah'
300 | ```
301 |
302 | - `treesit-fold-range-c-like-comment` - A shortcut for the large number of languages
303 | that have the c style comment structures `/*...*/` and `// ...`. Smartly picks
304 | the correct folding style for the comment on the line.
305 |
306 | ```c++
307 | /*
308 | * The main function that gets run after program is compiled
309 | * Doesn't take any parameters
310 | */
311 | int main() {
312 | // print hello world
313 | // and a new line
314 | printf("Hello, World\n");
315 | return 0;
316 | }
317 |
318 | // |
319 | // | '(comment . treesit-fold-range-c-like-comment)
320 | // V
321 |
322 | /* The main function that gets run after program is compiled */
323 | int main() {
324 | // print hello world
325 | printf("Hello, World\n");
326 | return 0;
327 | ```
328 |
329 | Now that you know what kinds of folds are easily available in treesit-fold, you can
330 | go ahead and add new fold definitions to `treesit-fold-range-alist` and be good to go!
331 |
332 | #### ❔ Example
333 |
334 | Let's look at a quick example of adding a new folding definition. Let's say you
335 | want to add folding to `go-mode`'s `field_declaration_list`. The folding
336 | definition that is needed will be
337 | `'(field_declaration_list . treesit-fold-range-seq)`. To add this to the
338 | `treesit-fold-range-alist`, you can do something like the following.
339 |
340 | ```emacs-lisp
341 | (push '(field_declaration_list . treesit-fold-range-seq) (alist-get 'go-mode treesit-fold-range-alist))
342 | ```
343 |
344 | Now the new fold definition should be usable by treesit-fold!
345 |
346 | #### ↔ Offset
347 |
348 | With the functions listed above you'll be able to define most folding behavior
349 | that you'll want for most languages. However, sometimes you'll have a language
350 | where the delimiter is a word instead of a single character bracket and you want
351 | to offset your fold by a certain amount to accommodate it. That's where offsets
352 | come in. When adding a fold definition to a a language's fold alist, you can
353 | either provide the folding function directly as you've seen so far:
354 |
355 | ```elisp
356 | '(block . treesit-fold-range-seq)
357 | ```
358 |
359 | Or you can provide the folding function with an offset:
360 |
361 | ```elisp
362 | '(block . (treesit-fold-range-seq 1 -3))
363 | ```
364 |
365 | When a range is provided, it provides extra room on the ends of a fold. The way
366 | this works is most easily shown using an example. Lets say we want to write a
367 | fold for bash's `for...do...done` construct to look something like this:
368 |
369 | ```sh
370 | for i in 1 2 3 4 5
371 | do
372 | echo "Welcome $i times"
373 | done
374 |
375 | # |
376 | # | '(do_group . )
377 | # V
378 |
379 | for i in 1 2 3 4 5
380 | do...done
381 | ```
382 |
383 | The `do...done` block is represented in tree-sitter as the node named
384 | `do_group`. However, if we just use `'(do_group . treesit-fold-range-seq)`, then
385 | we'll get results like the following:
386 |
387 | ```emacs-lisp
388 | for i in 1 2 3 4 5
389 | d...e
390 | ```
391 |
392 | which is hard to read. Instead, we can use the definition
393 | `'(do_group . (treesit-fold-range-seq 1 -3))` to offset the fold a bit to get our
394 | desired result!
395 |
396 | ### 🔍 Writing new fold functions
397 |
398 | If the built in functions don't fit your needs, you can write your own fold
399 | parser! Folding functions take two parameters:
400 |
401 | - `node` - the targeted tree-sitter node; in this example, `block` will be the
402 | targeting node.
403 | - `offset` - (optional) a cons of two integers. This is handy when you have
404 | a similar rule with little of positioning adjustment.
405 |
406 | Then the function needs to return a position range for the fold overlay in the
407 | form `'(start-of-fold . end-of-fold)`. If `nil` is returned instead of a range,
408 | then no fold is created. This can be useful if you want to add extra conditional
409 | logic onto your fold.
410 |
411 | As an example of a folding function, take a look at the definition of the
412 | basic `treesit-fold-range-seq`.
413 |
414 | ```elisp
415 | (defun treesit-fold-range-seq (node offset)
416 | "..."
417 | (let ((beg (1+ (treesit-node-start node))) ; node beginning position
418 | (end (1- (treesit-node-end node)))) ; node end position
419 | (treesit-fold--cons-add (cons beg end) offset))) ; return fold range
420 | ```
421 |
422 | ### 🔢 Line Count Display
423 |
424 | The following variables let you toggle and customize the display of the line count for folded regions.
425 |
426 | - `treesit-fold-line-count-show`
427 |
428 | This variable controls whether or not the number of lines in a folded text region is displayed.
429 |
430 | Type: `boolean`
431 |
432 | Default: `nil` (line count is not shown)
433 |
434 | If set to `t`, the number of lines in folded regions will be shown.
435 |
436 | Example:
437 | ```elisp
438 | (setq treesit-fold-line-count-show t) ; Show line count in folded regions
439 | ```
440 |
441 |
442 |
443 |
444 | - `treesit-fold-line-count-format`
445 |
446 | This variable defines the format string used for displaying the line
447 | count in folded text. The `%d` will be replaced with the actual number
448 | of lines in the folded region.
449 |
450 | Type: `string`
451 |
452 | Default: `(concat (truncate-string-ellipsis) " %d " (truncate-string-ellipsis))`
453 |
454 | Example:
455 |
456 | ```elisp
457 | (setq treesit-fold-line-count-format " <%d lines> ")
458 | ```
459 |
460 |
461 |
462 |
463 |
464 | ## 🔌 Plugins
465 |
466 | treesit-fold comes with a couple of useful little additions that can be used or
467 | turned off as desired.
468 |
469 | ### ⚖ Indicators Mode
470 |
471 |
472 |
473 |
474 |
475 | This plugin adds interactive visual markers in the gutter that show where folds
476 | can be made. They can be clicked on to fold or unfold given nodes.
477 |
478 | #### 💾 Installation
479 |
480 | `treesit-fold-indicator-mode` is loaded when `treesit-fold-mode` is and the functionality
481 | should be auto-loaded in, however if that's not working then you may want to
482 | explicitly declare the package in in your config.
483 |
484 | - `use-package`
485 |
486 | ```elisp
487 | (use-package treesit-fold-indicators
488 | :straight (treesit-fold-indicators :type git :host github :repo "emacs-tree-sitter/treesit-fold"))
489 | ```
490 |
491 | - ```elisp
492 | (add-to-list 'load-path "/path/to/lib")
493 | (require treesit-fold)
494 | ```
495 |
496 | or
497 |
498 | ```elisp
499 | (use-package treesit-fold-indicators
500 | :load-path "/path/to/lib")
501 | ```
502 |
503 | #### 🖥 Usage
504 |
505 | You can then enable this manually by doing either of the following:
506 |
507 | ```
508 | M-x treesit-fold-indicators-mode
509 |
510 | M-x global-treesit-fold-indicators-mode
511 | ```
512 |
513 | Please note that turning on `treesit-fold-indicators-mode` automatically turns on
514 | `treesit-fold-mode` as well. Though, turning off `treesit-fold-indicators-mode` does not
515 | turn off `treesit-fold-mode`
516 |
517 | - To enable this automatically whenever a buffer has a tree-sitter parser, use the global indicator mode:
518 |
519 | ```elisp
520 | (global-treesit-fold-indicators-mode 1)
521 | ```
522 |
523 | Else, you can add a hook directly.
524 |
525 | ```elisp
526 | (add-hook 'c-ts-mode-hook #'treesit-fold-indicators-mode)
527 | ```
528 |
529 | - To switch to left/right fringe: (Default is `left-fringe`)
530 |
531 | ```elisp
532 | (setq treesit-fold-indicators-fringe 'right-fringe)
533 | ```
534 |
535 | - To lower/higher the fringe overlay's priority: (Default is `30`)
536 |
537 | ```elisp
538 | (setq treesit-fold-indicators-priority 30)
539 | ```
540 |
541 | - To apply different faces depending on some conditions: (Default is `nil`)
542 |
543 | For example, to coordinate [line-reminder](https://github.com/emacs-vs/line-reminder)
544 | with this plugin.
545 |
546 | ```elisp
547 | (setq treesit-fold-indicators-face-function
548 | (lambda (pos &rest _)
549 | ;; Return the face of it's function.
550 | (line-reminder--get-face (line-number-at-pos pos t))))
551 |
552 | (setq line-reminder-add-line-function
553 | (lambda (&rest _)
554 | (null (treesit-fold--overlays-in treesit-fold-indicators-window (selected-window)
555 | (line-beginning-position) (line-end-position)))))
556 | ```
557 |
558 | ### 📝 Summary
559 |
560 |
561 |
562 |
563 |
564 | This plugin automatically extracts summary from the comment/document string,
565 | so you can have a nice way to peek at what's inside the fold range.
566 |
567 | #### 🖥 Usage
568 |
569 | - If you don't want this to happen, do: (Default is `t`)
570 |
571 | ```elisp
572 | (setq treesit-fold-summary-show nil)
573 | ```
574 |
575 | - Summary are truncated by length: (Default is `60`)
576 |
577 | ```elisp
578 | (setq treesit-fold-summary-max-length 60)
579 | ```
580 |
581 | - The exceeding string are replace by: (Default is `"..."`)
582 |
583 | ```elisp
584 | (setq treesit-fold-summary-exceeded-string "...")
585 | ```
586 |
587 | - To change summary format: (Default is `" %s "`)
588 |
589 | ```elisp
590 | (setq treesit-fold-summary-format " %s ")
591 | ```
592 |
593 | #### 📝 Customization
594 |
595 | Just like with fold definitions, you can create your own summary definitions.
596 | Summary definitions are defined in `treesit-fold-summary-parsers-alist` and has one
597 | summary function per major mode `'(java-mode . fold-summary-function)`. The
598 | summary function takes in the doc string which is all the text from a doc node
599 | and then returns a string to be displayed in its stead. Unlike with the folding
600 | functions, there aren't a set of general summary functions to fall back on.
601 | However, there are lots of examples and helper functions present in
602 | `treesit-fold-summary.el`. Let's look at one example here.
603 |
604 | ```emacs-lisp
605 | (defun treesit-fold-summary-javadoc (doc-str)
606 | "Extract summary from DOC-STR in Javadoc."
607 | (treesit-fold-summary--generic doc-str "*")) ;; strip the '*' and returns the first line
608 | ```
609 |
610 | As can be seen `treesit-fold-summary--generic` is a very helpful function since it
611 | removes the provided delimiter and returns the first line. often this will be
612 | enough.
613 |
614 | ### 🌫 Line-Comment folding
615 |
616 |
617 |
618 |
619 |
620 | This plugin makes line comment into foldable range.
621 |
622 | #### 🖥 Usage
623 |
624 | ```
625 | M-x treesit-fold-line-comment-mode
626 | ```
627 |
628 | ## 🔰 Contribute
629 |
630 | [](http://makeapullrequest.com)
631 | [](https://github.com/bbatsov/emacs-lisp-style-guide)
632 | [](https://www.paypal.me/jcs090218)
633 | [](https://www.patreon.com/jcs090218)
634 |
635 | Ensure your buffer has a tree-sitter parser first, then `treesit-explore-mode` is useful to test
636 | out queries that determine what syntax nodes should be foldable and how to fold
637 | them. [Emacs repository](https://git.savannah.gnu.org/cgit/emacs.git/tree/admin/notes/tree-sitter/starter-guide#n130) and [Emacs tree-sitter manual](https://www.gnu.org/software/emacs/manual/html_node/elisp/Pattern-Matching.html)
638 | has an excellent documentation on how to write `tree-sitter` queries.
639 |
640 | ### 🔬 Development
641 |
642 | To run the test locally, you will need the following tools:
643 |
644 | - [Eask](https://emacs-eask.github.io/)
645 | - [Make](https://www.gnu.org/software/make/) (optional)
646 |
647 | Install all dependencies and development dependencies:
648 |
649 | ```sh
650 | eask install-deps --dev
651 | ```
652 |
653 | To test the package's installation:
654 |
655 | ```sh
656 | eask package
657 | eask install
658 | ```
659 |
660 | To test compilation:
661 |
662 | ```sh
663 | eask compile
664 | ```
665 |
666 | **🪧 The following steps are optional, but we recommend you follow these lint results!**
667 |
668 | The built-in `checkdoc` linter:
669 |
670 | ```sh
671 | eask lint checkdoc
672 | ```
673 |
674 | The standard `package` linter:
675 |
676 | ```sh
677 | eask lint package
678 | ```
679 |
680 | *📝 P.S. For more information, find the Eask manual at https://emacs-eask.github.io/.*
681 |
682 | ### ❓ How to add a folding parser?
683 |
684 | When adding a new folding parser, add the folding definition function to
685 | `treesit-fold.el` itself near where the other range functions live and then add the
686 | parser to `treesit-fold-parsers.el` file. Finally, if you are adding support for a
687 | new language, remember to add it to the `treesit-fold-range-alist` variable.
688 |
689 | When creating a new parser, name it `treesit-fold-parsers-`.
690 |
691 | When creating a new folding function, name it
692 | `treesit-fold-range--` or something similar.
693 |
694 | #### 🔍 Where can I look for tree-sitter node?
695 |
696 | Here are some techniques for finding your desired nodes in tree-sitter.
697 |
698 | To look for the correct node you have three options:
699 |
700 | - look at the `tree-sitter-[lang]/grammar.js` implementation. In the above
701 | example, `block` node is defined in the
702 | [tree-sitter-c-sharp](https://github.com/tree-sitter/tree-sitter-c-sharp)'s
703 | `grammar.js` file.
704 | - open a file of your language choice (ensure that it has a tree-sitter parser) in emacs and `M-x treesit-explore-mode`.
705 | This will display a buffer with the whole s-expr representing nodes at point from the current file/buffer.
706 | - `M-x treesit-inspect-node-at-point` in your function to display what your
707 | function is seeing.
708 | - use `M-x treesit-inspect-mode` which diplay in the mode-line the current node at point.
709 |
710 | > [!WARNING]
711 | >
712 | > Make sure you look into the correct repository. Some repositories are managed
713 | > under https://github.com/tree-sitter/[lang].
714 |
715 | ### ❓ How to create a summary parser?
716 |
717 | `treesit-fold-summary.el` module is used to extract and display a short description
718 | from the comment/docstring.
719 |
720 | To create a summary parser, you just have to create a function that could
721 | extract comment syntax correctly then register this function to
722 | `treesit-fold-summary-parsers-alist` defined in `treesit-fold-summary.el`.
723 | The display and shortening will be handled by the module itself.
724 |
725 | Functions should be named with the prefix `treesit-fold-summary-` followed by
726 | `style name`. For example, to create a summary parser for Javadoc style, then it
727 | should be named `treesit-fold-summary-javadoc`.
728 |
729 | ## ⚜️ License
730 |
731 | This program is free software; you can redistribute it and/or modify
732 | it under the terms of the GNU General Public License as published by
733 | the Free Software Foundation, either version 3 of the License, or
734 | (at your option) any later version.
735 |
736 | This program is distributed in the hope that it will be useful,
737 | but WITHOUT ANY WARRANTY; without even the implied warranty of
738 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
739 | GNU General Public License for more details.
740 |
741 | You should have received a copy of the GNU General Public License
742 | along with this program. If not, see .
743 |
744 | See [`LICENSE`](./LICENSE.txt) for details.
745 |
746 |
747 |
748 |
749 | [ts-fold]: https://github.com/emacs-tree-sitter/ts-fold
750 | [treesit-fold]: https://github.com/emacs-tree-sitter/treesit-fold
751 |
752 | [tree-sitter.el]: https://github.com/emacs-tree-sitter/elisp-tree-sitter
753 | [treesit.el]: https://www.gnu.org/software/emacs/manual/html_node/elisp/Language-Grammar.html
754 |
--------------------------------------------------------------------------------
/_scripts/clean.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | cd ..
4 |
5 | del /s *.elc
6 |
--------------------------------------------------------------------------------
/_scripts/clean.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd ..
4 |
5 | find . -name "*.elc" -type f -delete
6 |
--------------------------------------------------------------------------------
/etc/indicators.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emacs-tree-sitter/treesit-fold/5b76926c14436b252150f88a8cd7e125ab295bcb/etc/indicators.png
--------------------------------------------------------------------------------
/etc/line-comment.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emacs-tree-sitter/treesit-fold/5b76926c14436b252150f88a8cd7e125ab295bcb/etc/line-comment.gif
--------------------------------------------------------------------------------
/etc/line-count-custom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emacs-tree-sitter/treesit-fold/5b76926c14436b252150f88a8cd7e125ab295bcb/etc/line-count-custom.png
--------------------------------------------------------------------------------
/etc/line-count-default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emacs-tree-sitter/treesit-fold/5b76926c14436b252150f88a8cd7e125ab295bcb/etc/line-count-default.png
--------------------------------------------------------------------------------
/etc/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emacs-tree-sitter/treesit-fold/5b76926c14436b252150f88a8cd7e125ab295bcb/etc/screenshot.png
--------------------------------------------------------------------------------
/etc/summary.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emacs-tree-sitter/treesit-fold/5b76926c14436b252150f88a8cd7e125ab295bcb/etc/summary.gif
--------------------------------------------------------------------------------
/treesit-fold-indicators.el:
--------------------------------------------------------------------------------
1 | ;;; treesit-fold-indicators.el --- Display indicators for folding range -*- lexical-binding: t; -*-
2 |
3 | ;; Copyright (C) 2021-2025 emacs-tree-sitter maintainers
4 |
5 | ;; Created date 2021-10-04 20:03:12
6 |
7 | ;; This file is NOT part of GNU Emacs.
8 |
9 | ;; This program is free software; you can redistribute it and/or modify
10 | ;; it under the terms of the GNU General Public License as published by
11 | ;; the Free Software Foundation, either version 3 of the License, or
12 | ;; (at your option) any later version.
13 |
14 | ;; This program is distributed in the hope that it will be useful,
15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | ;; GNU General Public License for more details.
18 |
19 | ;; You should have received a copy of the GNU General Public License
20 | ;; along with this program. If not, see .
21 |
22 | ;;; Commentary:
23 | ;;
24 | ;; Display indicators for folding range
25 | ;;
26 |
27 | ;;; Code:
28 |
29 | (require 'cl-lib)
30 | (require 'seq)
31 | (require 'subr-x)
32 |
33 | (require 'treesit-fold-util)
34 | (require 'treesit-fold)
35 |
36 | (defcustom treesit-fold-indicators-fringe 'left-fringe
37 | "Display indicators on the left/right fringe."
38 | :type '(choice (const :tag "On the right fringe" right-fringe)
39 | (const :tag "On the left fringe" left-fringe))
40 | :group 'treesit-fold)
41 |
42 | (defcustom treesit-fold-indicators-priority 30
43 | "Indicators overlay's priority."
44 | :type 'integer
45 | :group 'treesit-fold)
46 |
47 | (defcustom treesit-fold-indicators-face-function nil
48 | "Function call when apply to indicators face."
49 | :type 'function
50 | :group 'treesit-fold)
51 |
52 | ;; TODO: We eventually want to remove this. Therefore, we get fast and
53 | ;; accurate results!
54 | (defcustom treesit-fold-indicators-render-method 'partial
55 | "Method used to display indicators."
56 | :type '(choice (const :tag "Accurate rendering but cost more performance" full)
57 | (const :tag "Inaccurate rendering but fast" partial))
58 | :group 'treesit-fold)
59 |
60 | (defcustom treesit-fold-indicators-refresh-hook nil
61 | "Hook run after indicators refresh."
62 | :type 'hook
63 | :group 'treesit-fold)
64 |
65 | (define-fringe-bitmap 'treesit-fold-indicators-fr-plus
66 | (vector #b1111111
67 | #b1000001
68 | #b1001001
69 | #b1011101
70 | #b1001001
71 | #b1000001
72 | #b1111111))
73 |
74 | (define-fringe-bitmap 'treesit-fold-indicators-fr-minus-tail
75 | (vector #b00000000 #b00000000 #b00000000 #b00000000 #b00000000
76 | #b00000000 #b00000000 #b00000000 #b00000000 #b00000000
77 | #b1111111
78 | #b1000001
79 | #b1000001
80 | #b1011101
81 | #b1000001
82 | #b1000001
83 | #b1111111
84 | #b00011000 #b00011000 #b00011000 #b00011000 #b00011000
85 | #b00011000 #b00011000 #b00011000 #b00011000 #b00011000))
86 |
87 | (define-fringe-bitmap 'treesit-fold-indicators-fr-center
88 | (vector #b00011000 #b00011000 #b00011000 #b00011000 #b00011000
89 | #b00011000 #b00011000 #b00011000 #b00011000 #b00011000
90 | #b00011000 #b00011000 #b00011000 #b00011000 #b00011000
91 | #b00011000 #b00011000 #b00011000 #b00011000 #b00011000
92 | #b00011000 #b00011000 #b00011000))
93 |
94 | (define-fringe-bitmap 'treesit-fold-indicators-fr-end-left
95 | (vector #b00011000 #b00011000 #b00011000 #b00011000 #b00011000
96 | #b00011000 #b00011000 #b00011000 #b00011000 #b00011000
97 | #b00011000 #b00011111 #b00011111
98 | #b00000000 #b00000000 #b00000000 #b00000000 #b00000000
99 | #b00000000 #b00000000 #b00000000 #b00000000 #b00000000))
100 |
101 | (define-fringe-bitmap 'treesit-fold-indicators-fr-end-right
102 | (vector #b00011000 #b00011000 #b00011000 #b00011000 #b00011000
103 | #b00011000 #b00011000 #b00011000 #b00011000 #b00011000
104 | #b00011000 #b11111000 #b11111000
105 | #b00000000 #b00000000 #b00000000 #b00000000 #b00000000
106 | #b00000000 #b00000000 #b00000000 #b00000000 #b00000000))
107 |
108 | ;;
109 | ;; (@* "Entry" )
110 | ;;
111 |
112 | (defvar treesit-fold-indicators-mode-map
113 | (let ((map (make-sparse-keymap)))
114 | (define-key map [left-fringe mouse-1] #'treesit-fold-indicators-click-fringe)
115 | (define-key map [right-fringe mouse-1] #'treesit-fold-indicators-click-fringe)
116 | map)
117 | "Keymap for function `treesit-fold-indicators-mode'.")
118 |
119 | (defun treesit-fold-indicators--enable ()
120 | "Enable `treesit-fold-indicators' mode."
121 | (add-hook 'after-change-functions #'treesit-fold-indicators--trigger-render nil t)
122 | (add-hook 'after-save-hook #'treesit-fold-indicators--trigger-render nil t)
123 | (add-hook 'post-command-hook #'treesit-fold-indicators--post-command nil t)
124 | (add-hook 'window-size-change-functions #'treesit-fold-indicators--size-change)
125 | (add-hook 'window-scroll-functions #'treesit-fold-indicators--scroll)
126 | (treesit-fold-indicators--render-buffer))
127 |
128 | (defun treesit-fold-indicators--disable ()
129 | "Disable `treesit-fold-indicators' mode."
130 | (remove-hook 'after-change-functions #'treesit-fold-indicators--trigger-render t)
131 | (remove-hook 'after-save-hook #'treesit-fold-indicators--trigger-render t)
132 | (remove-hook 'post-command-hook #'treesit-fold-indicators--post-command t)
133 | (remove-hook 'window-size-change-functions #'treesit-fold-indicators--size-change)
134 | (remove-hook 'window-scroll-functions #'treesit-fold-indicators--scroll)
135 | (treesit-fold-indicators--remove-ovs-buffer))
136 |
137 | ;;;###autoload
138 | (define-minor-mode treesit-fold-indicators-mode
139 | "Minor mode for display fringe folding indicators."
140 | :group 'treesit-fold
141 | :lighter nil
142 | :keymap treesit-fold-indicators-mode-map
143 | :init-value nil
144 | (cond
145 | ((not (and (or treesit-fold-mode (treesit-fold-mode 1))
146 | treesit-fold-indicators-mode))
147 | (when treesit-fold-indicators-mode
148 | (treesit-fold-indicators-mode -1)))
149 | (treesit-fold-indicators-mode
150 | (treesit-fold-indicators--enable) t)
151 | (t
152 | (treesit-fold-indicators--disable))))
153 |
154 | ;;;###autoload
155 | (define-globalized-minor-mode global-treesit-fold-indicators-mode
156 | treesit-fold-indicators-mode treesit-fold-indicators--trigger
157 | :group 'treesit-fold)
158 |
159 | (defun treesit-fold-indicators--trigger ()
160 | "Enable `treesit-fold-indicators-mode' when the `treesit-fold-mode' can
161 | be enabled."
162 | (when (or treesit-fold-mode
163 | (treesit-fold-mode 1))
164 | (treesit-fold-indicators-mode 1)))
165 | ;;
166 | ;; (@* "Events" )
167 | ;;
168 |
169 | (defun treesit-fold-indicators-click-fringe (event)
170 | "EVENT click on fringe."
171 | (interactive "e")
172 | (let ((current-fringe (nth 1 (car (cdr event)))) ovs ov cur-ln)
173 | (when (eq current-fringe treesit-fold-indicators-fringe)
174 | (mouse-set-point event)
175 | (beginning-of-line)
176 | (setq cur-ln (line-number-at-pos (point)))
177 | (setq ovs (append (treesit-fold--overlays-in 'type 'treesit-fold-indicators-fr-plus)
178 | (treesit-fold--overlays-in 'type 'treesit-fold-indicators-fr-minus-tail)))
179 | (when ovs
180 | (setq ov (cl-some
181 | (lambda (ov) (= cur-ln (line-number-at-pos (overlay-start ov))))
182 | ovs))
183 | (when ov
184 | (or (save-excursion
185 | (end-of-line)
186 | (when (nth 4 (syntax-ppss)) (back-to-indentation))
187 | (treesit-fold-toggle))
188 | (treesit-fold-toggle)))))))
189 |
190 | ;;
191 | ;; (@* "Core" )
192 | ;;
193 |
194 | (defun treesit-fold-indicators--create-overlay-at-point ()
195 | "Create indicator overlay at current point."
196 | (let* ((pos (line-beginning-position))
197 | (ov (make-overlay pos (1+ pos)))
198 | (window (selected-window)))
199 | (overlay-put ov 'treesit-fold-indicators-window window)
200 | (overlay-put ov 'window window)
201 | ov))
202 |
203 | (defun treesit-fold-indicators--create-overlays (beg end folded)
204 | "Create indicators overlays in range of BEG to END.
205 |
206 | If argument FOLDED is non-nil, means the region is close/hidden (overlay
207 | is created); this is used to determie what indicators' bitmap to use."
208 | (let (ov-lst)
209 | (save-excursion
210 | (goto-char beg)
211 | (while (and (<= (line-beginning-position) end) (not (eobp)))
212 | (push (treesit-fold-indicators--create-overlay-at-point) ov-lst)
213 | (forward-line 1)))
214 | (treesit-fold-indicators--update-overlays (reverse ov-lst) folded)))
215 |
216 | (defun treesit-fold-indicators--get-priority (bitmap)
217 | "Return the priority integer depends on the type of the BITMAP.
218 |
219 | This is a static/constant method."
220 | (let ((prior treesit-fold-indicators-priority))
221 | (cl-case bitmap
222 | (treesit-fold-indicators-fr-plus (+ prior 2))
223 | (treesit-fold-indicators-fr-minus-tail (+ prior 2))
224 | (treesit-fold-indicators-fr-end-left (+ prior 1))
225 | (treesit-fold-indicators-fr-end-right (+ prior 1))
226 | (t prior))))
227 |
228 | (defun treesit-fold-indicators--get-string (folded ov bitmap)
229 | "Return a string or nil for indicators overlay (OV).
230 |
231 | If argument FOLDED is nil, it must return a string so all indicators are shown
232 | in range. Otherwise, we should only return string only when BITMAP is the
233 | head (first line) of the region."
234 | (let* ((face (or (and (functionp treesit-fold-indicators-face-function)
235 | (funcall treesit-fold-indicators-face-function (overlay-start ov)))
236 | 'treesit-fold-fringe-face))
237 | (str (propertize "." 'display `(,treesit-fold-indicators-fringe ,bitmap ,face))))
238 | (if (not folded) str
239 | (cl-case bitmap
240 | (treesit-fold-indicators-fr-plus str) ; return string only in head
241 | (treesit-fold-indicators-fr-minus-tail nil)
242 | (treesit-fold-indicators-fr-end-left nil)
243 | (treesit-fold-indicators-fr-end-right nil)
244 | (t nil)))))
245 |
246 | (defun treesit-fold-indicators--active-ov (folded ov bitmap)
247 | "SHOW the indicator OV with BITMAP.
248 |
249 | Argument FOLDED holds folding state; it's a boolean."
250 | (when (overlayp ov)
251 | (overlay-put ov 'treesit-fold-indicators-active folded)
252 | (overlay-put ov 'type bitmap)
253 | (overlay-put ov 'priority (treesit-fold-indicators--get-priority bitmap))
254 | (overlay-put ov 'before-string (treesit-fold-indicators--get-string folded ov bitmap))))
255 |
256 | (defun treesit-fold-indicators--get-end-fringe ()
257 | "Return end fringe bitmap according to variable `treesit-fold-indicators-fringe'."
258 | (cl-case treesit-fold-indicators-fringe
259 | (left-fringe 'treesit-fold-indicators-fr-end-left)
260 | (right-fringe 'treesit-fold-indicators-fr-end-right)
261 | (t (user-error "Invalid indicators fringe type: %s" treesit-fold-indicators-fringe))))
262 |
263 | (defun treesit-fold-indicators--update-overlays (ov-lst folded)
264 | "SHOW indicators overlays OV-LST depends on FOLDED."
265 | (when-let* ((len (length ov-lst))
266 | ((> len 1))
267 | (len-1 (1- len))
268 | (first-ov (nth 0 ov-lst))
269 | (last-ov (nth len-1 ov-lst))
270 | (index 1))
271 | ;; Head
272 | (treesit-fold-indicators--active-ov
273 | folded first-ov
274 | (if folded 'treesit-fold-indicators-fr-plus
275 | 'treesit-fold-indicators-fr-minus-tail))
276 | ;; Last
277 | (treesit-fold-indicators--active-ov folded last-ov (treesit-fold-indicators--get-end-fringe))
278 | ;; In between `head' and `last'
279 | (while (< index len-1)
280 | (treesit-fold-indicators--active-ov folded (nth index ov-lst) 'treesit-fold-indicators-fr-center)
281 | (cl-incf index)))
282 | ov-lst)
283 |
284 | ;;
285 | ;; (@* "Update" )
286 | ;;
287 |
288 | (defvar-local treesit-fold-indicators--render-this-command-p nil
289 | "Set to non-nil if render current command.")
290 |
291 | (defun treesit-fold-indicators--create (node)
292 | "Create indicators using NODE."
293 | (when-let* ((range (treesit-fold--get-fold-range node))
294 | (beg (car range)) (end (cdr range)))
295 | (let ((folded (treesit-fold-overlay-at node)))
296 | (treesit-fold-indicators--create-overlays beg end folded))))
297 |
298 | (defun treesit-fold-indicators--size-change (&optional frame &rest _)
299 | "Render indicators for all visible windows from FRAME."
300 | (treesit-fold--with-no-redisplay
301 | (dolist (win (window-list frame)) (treesit-fold-indicators--render-window win))))
302 |
303 | (defun treesit-fold-indicators--scroll (&optional window &rest _)
304 | "Render indicators on WINDOW."
305 | (treesit-fold--with-no-redisplay
306 | (treesit-fold-indicators--render-window window)))
307 |
308 | (defun treesit-fold-indicators--render-buffer ()
309 | "Render indicators for current buffer."
310 | (dolist (window (get-buffer-window-list nil nil t))
311 | (treesit-fold-indicators--render-window window)))
312 |
313 | (defun treesit-fold-indicators--render-window (window)
314 | "Render indicators for WINDOW."
315 | (treesit-fold--with-selected-window window
316 | (ignore-errors (treesit-fold-indicators-refresh))))
317 |
318 | (defun treesit-fold-indicators--trigger-render (&rest _)
319 | "Trigger rendering on the next redisplay."
320 | (setq treesit-fold-indicators--render-this-command-p t)) ; Trigger render at the end.
321 |
322 | (defun treesit-fold-indicators--post-command ()
323 | "Post command."
324 | (when treesit-fold-indicators--render-this-command-p
325 | (treesit-fold-indicators-refresh)
326 | (setq treesit-fold-indicators--render-this-command-p nil)))
327 |
328 | (defun treesit-fold-indicators--within-window (node wend wstart)
329 | "Return nil if NODE is not within the current window display range.
330 |
331 | Arguments WEND and WSTART are the range for caching."
332 | (when-let*
333 | ((range (cl-case treesit-fold-indicators-render-method
334 | (`full
335 | (ignore-errors (treesit-fold--get-fold-range node)))
336 | (`partial (cons (treesit-node-start node)
337 | (treesit-node-end node)))
338 | (t
339 | (user-error "Invalid render method: %s" treesit-fold-indicators-render-method))))
340 | (start (car range))
341 | (end (cdr range))
342 | ((or (and (<= wstart start) (<= end wend)) ; with in range
343 | (and (<= wstart end) (<= start wstart)) ; just one above
344 | (and (<= wend end) (<= start wend))))) ; just one below
345 | node))
346 |
347 | ;;;###autoload
348 | (defun treesit-fold-indicators-refresh (&rest _)
349 | "Refresh indicators for all folding range."
350 | (when (and (ignore-errors (treesit-buffer-root-node)) treesit-fold-indicators-mode)
351 | (treesit-fold--ensure-ts
352 | (when-let*
353 | ((node (ignore-errors (treesit-buffer-root-node)))
354 | (patterns (seq-mapcat (lambda (fold-range) `((,(car fold-range)) @name))
355 | (alist-get major-mode treesit-fold-range-alist)))
356 | (query (ignore-errors
357 | (treesit-query-compile (treesit-node-language node) patterns)))
358 | (nodes-to-fold (treesit-query-capture node query))
359 | (wend (window-end nil t))
360 | (wstart (window-start))
361 | (nodes-to-fold
362 | (cl-remove-if-not (lambda (node)
363 | (ignore-errors
364 | (treesit-fold-indicators--within-window (cdr node) wend wstart)))
365 | nodes-to-fold))
366 | (mode-ranges (alist-get major-mode treesit-fold-range-alist))
367 | (nodes-to-fold
368 | (cl-remove-if (lambda (node)
369 | (treesit-fold--non-foldable-node-p (cdr node) mode-ranges))
370 | nodes-to-fold)))
371 | (treesit-fold-indicators--remove-ovs)
372 | (thread-last nodes-to-fold
373 | (mapcar #'cdr)
374 | (mapc #'treesit-fold-indicators--create))
375 | (run-hooks 'treesit-fold-indicators-refresh-hook)))))
376 |
377 | (defun treesit-fold-indicators--remove-ovs (&optional window)
378 | "Remove all indicators overlays in this WINDOW."
379 | (remove-overlays (point-min) (point-max) 'treesit-fold-indicators-window
380 | (or window (selected-window))))
381 |
382 | (defun treesit-fold-indicators--remove-ovs-buffer ()
383 | "Remove all indicators overlays for this buffer."
384 | (dolist (window (get-buffer-window-list nil nil t))
385 | (treesit-fold-indicators--remove-ovs window)))
386 |
387 | (provide 'treesit-fold-indicators)
388 | ;;; treesit-fold-indicators.el ends here
389 |
--------------------------------------------------------------------------------
/treesit-fold-parsers.el:
--------------------------------------------------------------------------------
1 | ;;; treesit-fold-parsers.el --- Adapter layer to Tree-Sitter -*- lexical-binding: t; -*-
2 |
3 | ;; Copyright (C) 2021-2025 emacs-tree-sitter maintainers
4 |
5 | ;; Created date 2021-10-04 17:45:48
6 |
7 | ;; This file is NOT part of GNU Emacs.
8 |
9 | ;; This program is free software; you can redistribute it and/or modify
10 | ;; it under the terms of the GNU General Public License as published by
11 | ;; the Free Software Foundation, either version 3 of the License, or
12 | ;; (at your option) any later version.
13 |
14 | ;; This program is distributed in the hope that it will be useful,
15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | ;; GNU General Public License for more details.
18 |
19 | ;; You should have received a copy of the GNU General Public License
20 | ;; along with this program. If not, see .
21 |
22 | ;;; Commentary:
23 | ;;
24 | ;; Adapter layer to Tree-Sitter
25 | ;;
26 | ;; This isn't a real parser implementation, but records down the rule
27 | ;; in order to let the Tree-Sitter to parse things correctly. Think of
28 | ;; the rule sets!
29 | ;;
30 |
31 | ;;; Code:
32 |
33 | ;;
34 | ;; (@* "Externals" )
35 | ;;
36 |
37 | ;; TODO(everyone): keep the forward declared alphabetically sorted
38 |
39 | (declare-function treesit-fold-range-seq "treesit-fold.el")
40 | (declare-function treesit-fold-range-line-comment "treesit-fold.el")
41 | (declare-function treesit-fold-range-block-comment "treesit-fold.el")
42 | (declare-function treesit-fold-range-c-like-comment "treesit-fold.el")
43 |
44 | (declare-function treesit-fold-range-asm-label "treesit-fold.el")
45 | (declare-function treesit-fold-range-beancount-transaction "treesit-fold.el")
46 | (declare-function treesit-fold-range-c-preproc-ifdef "treesit-fold.el")
47 | (declare-function treesit-fold-range-c-preproc-if "treesit-fold.el")
48 | (declare-function treesit-fold-range-c-preproc-elif "treesit-fold.el")
49 | (declare-function treesit-fold-range-c-preproc-else "treesit-fold.el")
50 | (declare-function treesit-fold-range-elisp-function "treesit-fold.el")
51 | (declare-function treesit-fold-range-elixir "treesit-fold.el")
52 | (declare-function treesit-fold-range-erlang-clause-body "treesit-fold.el")
53 | (declare-function treesit-fold-range-erlang-type-guards "treesit-fold.el")
54 | (declare-function treesit-fold-range-fish-function "treesit-fold.el")
55 | (declare-function treesit-fold-range-fish-if "treesit-fold.el")
56 | (declare-function treesit-fold-range-fish-case "treesit-fold.el")
57 | (declare-function treesit-fold-range-haskell-function "treesit-fold.el")
58 | (declare-function treesit-fold-range-html "treesit-fold.el")
59 | (declare-function treesit-fold-range-julia-function "treesit-fold.el")
60 | (declare-function treesit-fold-range-julia-if "treesit-fold.el")
61 | (declare-function treesit-fold-range-julia-let "treesit-fold.el")
62 | (declare-function treesit-fold-range-kotlin-when "treesit-fold.el")
63 | (declare-function treesit-fold-range-latex-environment "treesit-fold.el")
64 | (declare-function treesit-fold-range-latex-section "treesit-fold.el")
65 | (declare-function treesit-fold-range-lisp-function "treesit-fold.el")
66 | (declare-function treesit-fold-range-llvm-label "treesit-fold.el")
67 | (declare-function treesit-fold-range-llvm-mir-label "treesit-fold.el")
68 | (declare-function treesit-fold-range-lua-comment "treesit-fold.el")
69 | (declare-function treesit-fold-range-lua-function "treesit-fold.el")
70 | (declare-function treesit-fold-range-lua-if "treesit-fold.el")
71 | (declare-function treesit-fold-range-lua-elseif "treesit-fold.el")
72 | (declare-function treesit-fold-range-lua-else "treesit-fold.el")
73 | (declare-function treesit-fold-range-lua-do-loop "treesit-fold.el")
74 | (declare-function treesit-fold-range-lua-repeat "treesit-fold.el")
75 | (declare-function treesit-fold-range-make-recipe "treesit-fold.el")
76 | (declare-function treesit-fold-range-markdown-heading "treesit-fold.el")
77 | (declare-function treesit-fold-range-markdown-code-block "treesit-fold.el")
78 | (declare-function treesit-fold-range-markdown-html-block "treesit-fold.el")
79 | (declare-function treesit-fold-range-matlab-function "treesit-fold.el")
80 | (declare-function treesit-fold-range-matlab-statements "treesit-fold.el")
81 | (declare-function treesit-fold-range-matlab-blocks "treesit-fold.el")
82 | (declare-function treesit-fold-range-mermaid-diagram "treesit-fold.el")
83 | (declare-function treesit-fold-range-mermaid-block "treesit-fold.el")
84 | (declare-function treesit-fold-range-ocaml-comment "treesit-fold.el")
85 | (declare-function treesit-fold-range-ocaml-module-definition "treesit-fold.el")
86 | (declare-function treesit-fold-range-ocaml-type-definition "treesit-fold.el")
87 | (declare-function treesit-fold-range-ocaml-value-definition "treesit-fold.el")
88 | (declare-function treesit-fold-range-org-body "treesit-fold.el")
89 | (declare-function treesit-fold-range-clojure-function "treesit-fold.el")
90 | (declare-function treesit-fold-range-cmake-body "treesit-fold.el")
91 | (declare-function treesit-fold-range-editorconfig-section "treesit-fold.el")
92 | (declare-function treesit-fold-range-pascal-comment "treesit-fold.el")
93 | (declare-function treesit-fold-range-python-block "treesit-fold.el")
94 | (declare-function treesit-fold-range-python-def "treesit-fold.el")
95 | (declare-function treesit-fold-range-python-expression-statement "treesit-fold.el")
96 | (declare-function treesit-fold-range-rst-body "treesit-fold.el")
97 | (declare-function treesit-fold-range-ruby-class-def "treesit-fold.el")
98 | (declare-function treesit-fold-range-ruby-if "treesit-fold.el")
99 | (declare-function treesit-fold-range-rust-macro "treesit-fold.el")
100 | (declare-function treesit-fold-range-sql-block "treesit-fold.el")
101 | (declare-function treesit-fold-range-toml-table "treesit-fold.el")
102 | (declare-function treesit-fold-range-verilog-list "treesit-fold.el")
103 | (declare-function treesit-fold-range-verilog-initial-construct "treesit-fold.el")
104 | (declare-function treesit-fold-range-verilog-module "treesit-fold.el")
105 | (declare-function treesit-fold-range-vhdl-package "treesit-fold.el")
106 | (declare-function treesit-fold-range-vhdl-type "treesit-fold.el")
107 |
108 | ;;
109 | ;; (@* "Parsers" )
110 | ;;
111 |
112 | ;; Should these functions be variables?
113 | ;; TODO(everyone): keep the function alphabetically sorted
114 |
115 | (defun treesit-fold-parsers-actionscript ()
116 | "Rule set for ActionScript."
117 | '((statement_block . treesit-fold-range-seq)
118 | (line_comment . treesit-fold-range-c-like-comment)
119 | (block_comment . treesit-fold-range-c-like-comment)))
120 |
121 | (defun treesit-fold-parsers-agda ()
122 | "Rule set for Agda."
123 | '(()))
124 |
125 | (defun treesit-fold-parsers-arduino ()
126 | "Rule set for Arduino."
127 | (append (treesit-fold-parsers-c++)))
128 |
129 | (defun treesit-fold-parsers-asm ()
130 | "Rule set for Assembly."
131 | '((label . treesit-fold-range-asm-label)
132 | (block_comment . treesit-fold-range-c-like-comment)
133 | (line_comment
134 | . (lambda (node offset)
135 | (let ((text (treesit-node-text node)))
136 | (cond ((string-prefix-p ";;" text)
137 | (treesit-fold-range-line-comment node offset ";;"))
138 | ((string-prefix-p "#" text)
139 | (treesit-fold-range-line-comment node offset "#"))
140 | (t
141 | (treesit-fold-range-c-like-comment node offset))))))))
142 |
143 | (defun treesit-fold-parsers-awk ()
144 | "Rule set for Awk."
145 | ;; TODO: Complete this function
146 | (append (treesit-fold-parsers-c)))
147 |
148 | (defun treesit-fold-parsers-bash ()
149 | "Rule set for Bash."
150 | '((compound_statement . treesit-fold-range-seq)
151 | (do_group . (treesit-fold-range-seq 1 -3))
152 | (comment
153 | . (lambda (node offset)
154 | (treesit-fold-range-line-comment node offset "#")))))
155 |
156 | (defun treesit-fold-parsers-beancount ()
157 | "Rule set for Beancount."
158 | '((transaction . treesit-fold-range-beancount-transaction)
159 | (comment
160 | . (lambda (node offset)
161 | (treesit-fold-range-line-comment node offset ";;")))))
162 |
163 | (defun treesit-fold-parsers-c ()
164 | "Rule set for C."
165 | '((compound_statement . treesit-fold-range-seq)
166 | (declaration_list . treesit-fold-range-seq)
167 | (enumerator_list . treesit-fold-range-seq)
168 | (field_declaration_list . treesit-fold-range-seq)
169 | (preproc_if . treesit-fold-range-c-preproc-if)
170 | (preproc_ifdef . treesit-fold-range-c-preproc-ifdef)
171 | (preproc_elif . treesit-fold-range-c-preproc-elif)
172 | (preproc_else . treesit-fold-range-c-preproc-else)
173 | (comment . treesit-fold-range-c-like-comment)))
174 |
175 | (defun treesit-fold-parsers-c++ ()
176 | "Rule set for C++."
177 | (append (treesit-fold-parsers-c)))
178 |
179 | (defun treesit-fold-parsers-clojure ()
180 | "Rule set for Clojure."
181 | '((list_lit . treesit-fold-range-clojure-function)
182 | (map_lit . treesit-fold-range-seq)
183 | (str_lit . treesit-fold-range-seq)
184 | (comment
185 | . (lambda (node offset)
186 | (treesit-fold-range-line-comment node
187 | (treesit-fold--cons-add offset '(0 . -1))
188 | ";;")))))
189 |
190 | (defun treesit-fold-parsers-cmake ()
191 | "Rule set for CMake."
192 | '((body . treesit-fold-range-cmake-body)
193 | (line_comment
194 | . (lambda (node offset)
195 | (treesit-fold-range-line-comment node offset "#")))))
196 |
197 | (defun treesit-fold-parsers-csharp ()
198 | "Rule set for C#."
199 | '((block . treesit-fold-range-seq)
200 | (accessor_list . treesit-fold-range-seq)
201 | (enum_member_declaration_list . treesit-fold-range-seq)
202 | (declaration_list . treesit-fold-range-seq)
203 | (switch_body . treesit-fold-range-seq)
204 | (anonymous_object_creation_expression . treesit-fold-range-seq)
205 | (initializer_expression . treesit-fold-range-seq)
206 | ;;(if_directive . treesit-fold-range-seq)
207 | ;;(else_directive . treesit-fold-range-seq)
208 | ;;(elif_directive . treesit-fold-range-seq)
209 | ;;(endif_directive . treesit-fold-range-seq)
210 | ;;(region_directive . treesit-fold-range-seq)
211 | ;;(endregion_directive . treesit-fold-range-seq)
212 | (comment . treesit-fold-range-c-like-comment)))
213 |
214 | (defun treesit-fold-parsers-css ()
215 | "Rule set for CSS."
216 | '((keyframe_block_list . treesit-fold-range-seq)
217 | (block . treesit-fold-range-seq)
218 | (comment . treesit-fold-range-c-like-comment)))
219 |
220 | (defun treesit-fold-parsers-dart ()
221 | "Rule set for Dart."
222 | '((block . treesit-fold-range-seq)
223 | (class_body . treesit-fold-range-seq)
224 | (arguments . treesit-fold-range-seq)
225 | (comment . treesit-fold-range-c-like-comment)
226 | (documentation_comment . treesit-fold-range-c-like-comment)
227 | (list_literal . treesit-fold-range-seq))) ; array
228 |
229 | (defun treesit-fold-parsers-editorconfig ()
230 | "Rule set for EditorConfig."
231 | '((section . treesit-fold-range-editorconfig-section)
232 | (comment
233 | . (lambda (node offset)
234 | (treesit-fold-range-line-comment node
235 | (treesit-fold--cons-add offset '(0 . -1))
236 | "#")))))
237 |
238 | (defun treesit-fold-parsers-elisp ()
239 | "Rule set for Elisp."
240 | '((macro_definition . treesit-fold-range-elisp-function)
241 | (function_definition . treesit-fold-range-elisp-function)
242 | (comment
243 | . (lambda (node offset)
244 | (treesit-fold-range-line-comment node offset ";;")))))
245 |
246 | (defun treesit-fold-parsers-elixir ()
247 | "Rules set for Elixir."
248 | '((list . treesit-fold-range-seq)
249 | (map . treesit-fold-range-seq)
250 | (tuple . treesit-fold-range-seq)
251 | (do_block . treesit-fold-range-elixir)
252 | (comment
253 | . (lambda (node offset)
254 | (treesit-fold-range-line-comment node offset "#")))))
255 |
256 | (defun treesit-fold-parsers-erlang ()
257 | "Rules set for Erlang."
258 | '((list . treesit-fold-range-seq)
259 | (clause_body . treesit-fold-range-erlang-clause-body)
260 | (type_guards . treesit-fold-range-erlang-type-guards)
261 | (comment
262 | . (lambda (node offset)
263 | (treesit-fold-range-line-comment node offset "%")))))
264 |
265 | (defun treesit-fold-parsers-fish ()
266 | "Rules set for Fish."
267 | '((function_definition . treesit-fold-range-fish-function)
268 | (if_statement . treesit-fold-range-fish-if)
269 | (switch_statement . treesit-fold-range-fish-if)
270 | (for_statement . treesit-fold-range-fish-if)
271 | (while_statement . treesit-fold-range-fish-if)
272 | (case_clause . treesit-fold-range-fish-case)
273 | (comment
274 | . (lambda (node offset)
275 | (treesit-fold-range-line-comment node offset "#")))))
276 |
277 | (defun treesit-fold-parsers-gdscript ()
278 | "Rule set for GGScript."
279 | '((body . (treesit-fold-range-seq -1 1))
280 | (comment
281 | . (lambda (node offset)
282 | (treesit-fold-range-line-comment node offset "#")))))
283 |
284 | (defun treesit-fold-parsers-gleam ()
285 | "Rules set for Gleam."
286 | '((function . treesit-fold-range-gleam)
287 | (type_definition . treesit-fold-range-gleam)
288 | (anonymous_function . treesit-fold-range-gleam)
289 | (block . treesit-fold-range-gleam)
290 | (list . treesit-fold-range-seq)
291 | (module_comment
292 | . (lambda (node offset)
293 | (treesit-fold-range-line-comment node offset "////")))
294 | (statement_comment
295 | . (lambda (node offset)
296 | (treesit-fold-range-line-comment node offset "///")))))
297 |
298 | (defun treesit-fold-parsers-glsl ()
299 | "Rule set for GLSL."
300 | '((field_declaration_list . treesit-fold-range-seq)
301 | (compound_statement . treesit-fold-range-seq)
302 | (comment . treesit-fold-range-c-like-comment)))
303 |
304 | (defun treesit-fold-parsers-go ()
305 | "Rule set for Go."
306 | '((block . treesit-fold-range-seq)
307 | (comment . treesit-fold-range-c-like-comment)
308 | (const_declaration . (lambda (node offset)
309 | (treesit-fold-range-markers node offset "(" ")")))
310 | (field_declaration_list . treesit-fold-range-seq)
311 | (import_spec_list . treesit-fold-range-seq)
312 | (interface_type . (lambda (node offset)
313 | (treesit-fold-range-markers node offset "{" "}")))))
314 |
315 | (defun treesit-fold-parsers-groovy ()
316 | "Rule set for Groovy."
317 | '((block . treesit-fold-range-groovy-block)
318 | (line_comment . treesit-fold-range-c-like-comment)
319 | (block_comment . treesit-fold-range-c-like-comment)))
320 |
321 | (defun treesit-fold-parsers-haskell ()
322 | "Rule set for Haskell."
323 | '((function . treesit-fold-range-haskell-function)
324 | (comment . treesit-fold-range-lua-comment)))
325 |
326 | (defun treesit-fold-parsers-haxe ()
327 | "Rule set for Haxe."
328 | '((block . treesit-fold-range-seq)
329 | (comment . treesit-fold-range-c-like-comment)))
330 |
331 | (defun treesit-fold-parsers-heex ()
332 | "Rule set for Heex."
333 | '((tag . treesit-fold-range-html)
334 | (component . treesit-fold-range-html)
335 | (comment . (treesit-fold-range-seq 1 -1))))
336 |
337 | (defun treesit-fold-parsers-hlsl ()
338 | "Rule set for HLSL."
339 | '((field_declaration_list . treesit-fold-range-seq)
340 | (compound_statement . treesit-fold-range-seq)
341 | (comment . treesit-fold-range-c-like-comment)))
342 |
343 | (defun treesit-fold-parsers-html ()
344 | "Rule set for HTML."
345 | '((element . treesit-fold-range-html)
346 | (comment . (treesit-fold-range-seq 1 -1))))
347 |
348 | (defun treesit-fold-parsers-jai ()
349 | "Rule set for Jai."
350 | '((imperative_scope . treesit-fold-range-seq)
351 | (data_scope . treesit-fold-range-seq)
352 | (block_comment . treesit-fold-range-block-comment)
353 | (inline_comment . treesit-fold-range-c-like-comment)))
354 |
355 | (defun treesit-fold-parsers-janet ()
356 | "Rule set for Janet."
357 | '((par_tup_lit . treesit-fold-range-seq)
358 | (sqr_tup_lit . treesit-fold-range-seq)
359 | (comment
360 | . (lambda (node offset)
361 | (treesit-fold-range-line-comment node offset "#")))))
362 |
363 | (defun treesit-fold-parsers-java ()
364 | "Rule set for Java."
365 | '((switch_block . treesit-fold-range-seq)
366 | (block . treesit-fold-range-seq)
367 | (element_value_array_initializer . treesit-fold-range-seq)
368 | (module_body . treesit-fold-range-seq)
369 | (enum_body . treesit-fold-range-seq)
370 | (class_body . treesit-fold-range-seq)
371 | (constructor_body . treesit-fold-range-seq)
372 | (annotation_type_body . treesit-fold-range-seq)
373 | (interface_body . treesit-fold-range-seq)
374 | (array_initializer . treesit-fold-range-seq)
375 | (block_comment . treesit-fold-range-block-comment)
376 | (line_comment . treesit-fold-range-c-like-comment)))
377 |
378 | (defun treesit-fold-parsers-javascript ()
379 | "Rule set for JavaScript."
380 | '((export_clause . treesit-fold-range-seq)
381 | (statement_block . treesit-fold-range-seq)
382 | (object . treesit-fold-range-seq)
383 | (array . treesit-fold-range-seq)
384 | (comment . treesit-fold-range-c-like-comment)))
385 |
386 | (defun treesit-fold-parsers-json ()
387 | "Rule set for JSON."
388 | '((object . treesit-fold-range-seq)
389 | (array . treesit-fold-range-seq)
390 | (comment . treesit-fold-range-c-like-comment)))
391 |
392 | (defun treesit-fold-parsers-jsonnet ()
393 | "Rule set for Jsonnet."
394 | '((object . treesit-fold-range-seq)
395 | (array . treesit-fold-range-seq)
396 | (comment . treesit-fold-range-c-like-comment)))
397 |
398 | (defun treesit-fold-parsers-julia ()
399 | "Rule set for Julia."
400 | '((block_comment . (treesit-fold-range-seq 1 -1))
401 | (for_statement . treesit-fold-range-julia-if)
402 | (function_definition . treesit-fold-range-julia-function)
403 | (if_statement . treesit-fold-range-julia-if)
404 | (let_statement . treesit-fold-range-julia-let)
405 | (macro_definition . treesit-fold-range-julia-function)
406 | (module_definition . treesit-fold-range-julia-function)
407 | (quote_statement . treesit-fold-range-julia-function)
408 | (struct_definition . treesit-fold-range-julia-function)
409 | (triple_string . (treesit-fold-range-seq 2 -2))
410 | (try_statement . (treesit-fold-range-seq 2 -2))
411 | (while_statement . treesit-fold-range-julia-function)
412 | (comment
413 | . (lambda (node offset)
414 | (treesit-fold-range-line-comment node offset "#")))))
415 |
416 | (defun treesit-fold-parsers-kotlin ()
417 | "Rule set for Kotlin."
418 | '((function_body . treesit-fold-range-seq)
419 | (control_structure_body . treesit-fold-range-seq)
420 | (lambda_literal . treesit-fold-range-seq)
421 | (enum_class_body . treesit-fold-range-seq)
422 | (class_body . treesit-fold-range-seq)
423 | (when_expression . treesit-fold-range-kotlin-when)
424 | (multiline_comment . treesit-fold-range-c-like-comment)
425 | (line_comment . treesit-fold-range-c-like-comment)))
426 |
427 | (defun treesit-fold-parsers-latex ()
428 | "Rule set for LaTex."
429 | '((generic_environment . treesit-fold-range-latex-environment)
430 | (math_environment . treesit-fold-range-latex-environment)
431 | (section . treesit-fold-range-latex-section)
432 | (subsection . treesit-fold-range-latex-section)
433 | (subsubsection . treesit-fold-range-latex-section)
434 | (curly_group . treesit-fold-range-seq)
435 | (line_comment
436 | . (lambda (node offset)
437 | (treesit-fold-range-line-comment node offset "%")))))
438 |
439 | (defun treesit-fold-parsers-lisp ()
440 | "Rule set for Lisp."
441 | '((defun . treesit-fold-range-lisp-function)
442 | (comment
443 | . (lambda (node offset)
444 | (treesit-fold-range-line-comment node
445 | (treesit-fold--cons-add offset '(0 . -1))
446 | ";;")))))
447 |
448 | (defun treesit-fold-parsers-llvm ()
449 | "Rule set for LLVM."
450 | '((function_body . treesit-fold-range-seq)
451 | (label . treesit-fold-range-llvm-label)
452 | (comment
453 | . (lambda (node offset)
454 | (treesit-fold-range-line-comment node offset ";;")))))
455 |
456 | (defun treesit-fold-parsers-llvm-mir ()
457 | "Rule set for LLVM MIR."
458 | '((basic_block . treesit-fold-range-llvm-mir-label)
459 | (comment
460 | . (lambda (node offset)
461 | (treesit-fold-range-line-comment node offset ";;")))))
462 |
463 | (defun treesit-fold-parsers-lua ()
464 | "Rule set for Lua."
465 | '((expression_list . treesit-fold-range-seq)
466 | (function_declaration . treesit-fold-range-lua-function)
467 | (if_statement . treesit-fold-range-lua-if)
468 | (elseif_statement . treesit-fold-range-lua-elseif)
469 | (else_statement . treesit-fold-range-lua-else)
470 | (while_statement . treesit-fold-range-lua-do-loop)
471 | (for_statement . treesit-fold-range-lua-do-loop)
472 | (repeat_statement . treesit-fold-range-lua-repeat)
473 | (comment . treesit-fold-range-lua-comment)))
474 |
475 | (defun treesit-fold-parsers-magik ()
476 | "Rule set for Magik."
477 | '((method . treesit-fold-range-seq)
478 | (comment
479 | . (lambda (node offset)
480 | (treesit-fold-range-line-comment node offset "#")))))
481 |
482 | (defun treesit-fold-parsers-make ()
483 | "Rule set for Make."
484 | '((recipe . treesit-fold-range-make-recipe)
485 | (comment
486 | . (lambda (node offset)
487 | (treesit-fold-range-line-comment node offset "#")))))
488 |
489 | (defun treesit-fold-parsers-markdown ()
490 | "Rule set for Markdown."
491 | '((fenced_code_block . treesit-fold-range-markdown-code-block)
492 | (section . treesit-fold-range-markdown-heading)
493 | (html_block . treesit-fold-range-markdown-html-block)))
494 |
495 | (defun treesit-fold-parsers-matlab ()
496 | "Rule set for MATLAB."
497 | '((expression_list . treesit-fold-range-seq)
498 | (function_definition . treesit-fold-range-matlab-function)
499 | (properties . treesit-fold-range-matlab-function)
500 | (methods . treesit-fold-range-matlab-function)
501 | (class_definition . treesit-fold-range-matlab-function)
502 | (if_statement . treesit-fold-range-matlab-statements)
503 | (elseif_clause . treesit-fold-range-matlab-statements)
504 | (else_clause . treesit-fold-range-matlab-statements)
505 | (for_statement . treesit-fold-range-matlab-statements)
506 | (while_statement . treesit-fold-range-matlab-statements)
507 | (switch_statement . treesit-fold-range-matlab-statements)
508 | (case_clause . treesit-fold-range-matlab-statements)
509 | (otherwise_clause . treesit-fold-range-matlab-statements)
510 | (try_statement . treesit-fold-range-matlab-statements)
511 | (catch_clause . treesit-fold-range-matlab-statements)
512 | (comment . treesit-fold-range-matlab-blocks)))
513 |
514 | (defun treesit-fold-parsers-mermaid ()
515 | "Rule set for Mermaid."
516 | '((diagram_flow . treesit-fold-range-mermaid-diagram)
517 | (diagram_sequence . treesit-fold-range-mermaid-diagram)
518 | (diagram_class . treesit-fold-range-mermaid-diagram)
519 | (diagram_er . treesit-fold-range-mermaid-diagram)
520 | (class_stmt_class . treesit-fold-range-mermaid-block)
521 | (er_stmt_entity_block . treesit-fold-range-mermaid-block)
522 | (comment
523 | . (lambda (node offset)
524 | (treesit-fold-range-line-comment node
525 | (treesit-fold--cons-add offset '(0 . -1))
526 | "%%")))))
527 |
528 | (defun treesit-fold-parsers-ninja ()
529 | "Rule set for Ninja."
530 | '((build . (treesit-fold-range-seq 4 0))
531 | (comment
532 | . (lambda (node offset)
533 | (treesit-fold-range-line-comment node
534 | (treesit-fold--cons-add offset '(0 . -1))
535 | "#")))))
536 |
537 | (defun treesit-fold-parsers-noir ()
538 | "Rule set for Noir."
539 | '((body . treesit-fold-range-seq)
540 | (comment . treesit-fold-range-c-like-comment)))
541 |
542 | (defun treesit-fold-parsers-nix ()
543 | "Rule set for Nix."
544 | '((attrset_expression . treesit-fold-range-seq)
545 | (interpolation . treesit-fold-range-seq)
546 | (list_expression . treesit-fold-range-seq)
547 | (comment
548 | . (lambda (node offset)
549 | (if (string-prefix-p "#" (treesit-node-text node))
550 | (treesit-fold-range-line-comment node offset "#")
551 | (treesit-fold-range-c-like-comment node offset))))))
552 |
553 | (defun treesit-fold-parsers-ocaml ()
554 | "Rule set for OCaml."
555 | '((comment . treesit-fold-range-ocaml-comment)
556 | (module_definition . treesit-fold-range-ocaml-module-definition)
557 | (type_definition . treesit-fold-range-ocaml-type-definition)
558 | (value_definition . treesit-fold-range-ocaml-value-definition)))
559 |
560 | (defun treesit-fold-parsers-org ()
561 | "Rule set for Org."
562 | '((body . treesit-fold-range-org-body)
563 | (block . treesit-fold-range-seq)
564 | (comment . treesit-fold-range-seq)))
565 |
566 | (defun treesit-fold-parsers-pascal ()
567 | "Rule set for Pascal."
568 | '((comment . treesit-fold-range-pascal-comment)))
569 |
570 | (defun treesit-fold-parsers-perl ()
571 | "Rule set for Perl."
572 | '((block . treesit-fold-range-seq)
573 | (list_expression . treesit-fold-range-seq)
574 | (comment
575 | . (lambda (node offset)
576 | (treesit-fold-range-line-comment node offset "#")))))
577 |
578 | (defun treesit-fold-parsers-php ()
579 | "Rule set for PHP."
580 | '((namespace_use_group . treesit-fold-range-seq)
581 | (declaration_list . treesit-fold-range-seq)
582 | (use_list . treesit-fold-range-seq)
583 | (switch_block . treesit-fold-range-seq)
584 | (compound_statement . treesit-fold-range-seq)
585 | (comment
586 | . (lambda (node offset)
587 | (if (string-prefix-p "#" (treesit-node-text node))
588 | (treesit-fold-range-line-comment node offset "#")
589 | (treesit-fold-range-c-like-comment node offset))))))
590 |
591 | (defun treesit-fold-parsers-python ()
592 | "Rule set for Python."
593 | '((import_statement . treesit-fold-range-seq)
594 | (import_from_statement . treesit-fold-range-seq)
595 | (future_import_statement . treesit-fold-range-seq)
596 | (function_definition . treesit-fold-range-python-def)
597 | (class_definition . treesit-fold-range-python-def)
598 | (while_statement . treesit-fold-range-python-block)
599 | (for_statement . treesit-fold-range-python-block)
600 | (if_statement . treesit-fold-range-python-block)
601 | (elif_clause . treesit-fold-range-python-block)
602 | (else_clause . treesit-fold-range-python-block)
603 | (match_statement . treesit-fold-range-python-block)
604 | (case_clause . treesit-fold-range-python-block)
605 | (try_statement . treesit-fold-range-python-block)
606 | (except_clause . treesit-fold-range-python-block)
607 | (with_statement . treesit-fold-range-python-block)
608 | (list . treesit-fold-range-seq)
609 | (dictionary . treesit-fold-range-seq)
610 | (parenthesized_expression . treesit-fold-range-seq)
611 | (expression_statement . treesit-fold-range-python-expression-statement)
612 | (comment
613 | . (lambda (node offset)
614 | (treesit-fold-range-line-comment node offset "#")))))
615 |
616 | (defun treesit-fold-parsers-qss ()
617 | "Rule set for QSS."
618 | (append (treesit-fold-parsers-css)))
619 |
620 | (defun treesit-fold-parsers-r ()
621 | "Rule set for R."
622 | '((brace_list . treesit-fold-range-seq)))
623 |
624 | (defun treesit-fold-parsers-rst ()
625 | "Rule set for reStructuredText."
626 | '((body . treesit-fold-range-rst-body)
627 | (comment . (treesit-fold-range-seq 1 0))))
628 |
629 | (defun treesit-fold-parsers-ruby ()
630 | "Rule set for Ruby."
631 | '((class . treesit-fold-range-ruby-class-def)
632 | (method . treesit-fold-range-ruby-class-def)
633 | (array . treesit-fold-range-seq)
634 | (do . (treesit-fold-range-seq 1 -2)) ; match with `end`
635 | (do_block . (treesit-fold-range-seq 1 -2)) ; match with `end`, in spec file
636 | (then . treesit-fold-range-ruby-if) ; `if` and `elsif` block
637 | (else . (treesit-fold-range-ruby-if 4 0)) ; `else` block
638 | (comment
639 | . (lambda (node offset)
640 | (treesit-fold-range-line-comment node offset "#")))))
641 |
642 | (defun treesit-fold-parsers-rust ()
643 | "Rule set for Rust."
644 | '((declaration_list . treesit-fold-range-seq)
645 | (enum_variant_list . treesit-fold-range-seq)
646 | (field_declaration_list . treesit-fold-range-seq)
647 | (use_list . treesit-fold-range-seq)
648 | (field_initializer_list . treesit-fold-range-seq)
649 | (match_block . treesit-fold-range-seq)
650 | (macro_definition . (treesit-fold-range-rust-macro 1 -1))
651 | (block . treesit-fold-range-seq)
652 | (token_tree . treesit-fold-range-seq)
653 | (line_comment
654 | . (lambda (node offset)
655 | (treesit-fold-range-line-comment node
656 | (treesit-fold--cons-add offset '(0 . -1))
657 | "///")))
658 | (block_comment . treesit-fold-range-block-comment)))
659 |
660 | (defun treesit-fold-parsers-scala ()
661 | "Rule set for Scala."
662 | '((import_selectors . treesit-fold-range-seq)
663 | (template_body . treesit-fold-range-seq)
664 | (block . treesit-fold-range-seq)
665 | (comment . treesit-fold-range-c-like-comment)))
666 |
667 | (defun treesit-fold-parsers-scheme ()
668 | "Rule set for Scheme."
669 | '((list . treesit-fold-range-seq)
670 | (comment
671 | . (lambda (node offset)
672 | (treesit-fold-range-line-comment node offset ";;")))))
673 |
674 | (defun treesit-fold-parsers-sql ()
675 | "Rule set for SQL."
676 | '((block . treesit-fold-range-sql-block)
677 | (subquery . treesit-fold-range-seq)
678 | (list . treesit-fold-range-seq)
679 | (column_definitions . treesit-fold-range-seq)
680 | (marginalia . treesit-fold-range-c-like-comment) ; This is the comment!
681 | (comment
682 | . (lambda (node offset)
683 | (treesit-fold-range-line-comment node offset "--")))))
684 |
685 | (defun treesit-fold-parsers-svelte ()
686 | "Rule set for Svelte."
687 | (append
688 | (treesit-fold-parsers-html)
689 | '((script_element . treesit-fold-range-html)
690 | (style_element . treesit-fold-range-html))))
691 |
692 | (defun treesit-fold-parsers-swift ()
693 | "Rule set for Swift."
694 | '((function_body . treesit-fold-range-seq)
695 | (class_body . treesit-fold-range-seq)
696 | (enum_class_body . treesit-fold-range-seq)
697 | (protocol_body . treesit-fold-range-seq)
698 | (multiline_comment . treesit-fold-range-c-like-comment)
699 | (comment . treesit-fold-range-c-like-comment)))
700 |
701 | (defun treesit-fold-parsers-tablegen ()
702 | "Rule set for Tablegen."
703 | '((record_body . treesit-fold-range-seq)
704 | (multiline_comment . treesit-fold-range-c-like-comment)
705 | (comment . treesit-fold-range-c-like-comment)))
706 |
707 | (defun treesit-fold-parsers-toml ()
708 | "Rule set for TOML."
709 | '((table . treesit-fold-range-toml-table)
710 | (array . treesit-fold-range-seq)
711 | (comment
712 | . (lambda (node offset)
713 | (treesit-fold-range-line-comment node offset "#")))))
714 |
715 | (defun treesit-fold-parsers-typescript ()
716 | "Rule set for TypeScript."
717 | (append
718 | (treesit-fold-parsers-javascript)
719 | '((class_body . treesit-fold-range-seq)
720 | (enum_body . treesit-fold-range-seq)
721 | (named_imports . treesit-fold-range-seq)
722 | (object_type . treesit-fold-range-seq))))
723 |
724 | (defun treesit-fold-parsers-verilog ()
725 | "Rule set for Verilog."
726 | '((module_declaration . treesit-fold-range-verilog-module)
727 | (list_of_port_connections . treesit-fold-range-verilog-list)
728 | (initial_construct . treesit-fold-range-verilog-initial-construct)
729 | (comment . treesit-fold-range-c-like-comment)))
730 |
731 | (defun treesit-fold-parsers-vhdl ()
732 | "Rule set for VHDL."
733 | '((package_declaration . treesit-fold-range-vhdl-package)
734 | (full_type_declaration . treesit-fold-range-vhdl-type)
735 | (enumeration_type_definition . treesit-fold-range-seq)
736 | (comment . treesit-fold-range-lua-comment)))
737 |
738 | (defun treesit-fold-parsers-vimscript ()
739 | "Rule set for Vimscript."
740 | '((function_definition . treesit-fold-range-vimscript-function)
741 | (if_statement . (treesit-fold-range-seq 1 -4))))
742 |
743 | (defun treesit-fold-parsers-xml ()
744 | "Rule set for XML."
745 | '((element . treesit-fold-range-html)
746 | (Comment . (treesit-fold-range-seq 3 -2))))
747 |
748 | (defun treesit-fold-parsers-yaml ()
749 | "Rule set for YAML."
750 | '((comment
751 | . (lambda (node offset)
752 | (treesit-fold-range-line-comment node offset "#")))
753 | (block_mapping_pair
754 | . ((lambda (node offset)
755 | (treesit-fold-range-markers node offset ":"))
756 | 0 1))))
757 |
758 | (defun treesit-fold-parsers-zig ()
759 | "Rule set for Zig."
760 | '((ErrorSetDecl . (lambda (node offset)
761 | (treesit-fold-range-markers node offset "{")))
762 | (ContainerDecl . (lambda (node offset)
763 | (treesit-fold-range-markers node offset "{")))
764 | (SwitchExpr . (lambda (node offset)
765 | (treesit-fold-range-markers node offset "{")))
766 | (Block . treesit-fold-range-seq)
767 | (InitList . treesit-fold-range-seq)
768 | (line_comment . treesit-fold-range-c-like-comment)))
769 |
770 | (provide 'treesit-fold-parsers)
771 | ;;; treesit-fold-parsers.el ends here
772 |
--------------------------------------------------------------------------------
/treesit-fold-summary.el:
--------------------------------------------------------------------------------
1 | ;;; treesit-fold-summary.el --- Extract summary from fold region -*- lexical-binding: t; -*-
2 |
3 | ;; Copyright (C) 2021-2025 emacs-tree-sitter maintainers
4 |
5 | ;; Created date 2021-10-04 16:59:22
6 |
7 | ;; This file is NOT part of GNU Emacs.
8 |
9 | ;; This program is free software; you can redistribute it and/or modify
10 | ;; it under the terms of the GNU General Public License as published by
11 | ;; the Free Software Foundation, either version 3 of the License, or
12 | ;; (at your option) any later version.
13 |
14 | ;; This program is distributed in the hope that it will be useful,
15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | ;; GNU General Public License for more details.
18 |
19 | ;; You should have received a copy of the GNU General Public License
20 | ;; along with this program. If not, see .
21 |
22 | ;;; Commentary:
23 | ;;
24 | ;; Extract summary from fold region.
25 | ;;
26 |
27 | ;;; Code:
28 |
29 | (require 'mule-util)
30 |
31 | (require 'treesit-fold-util)
32 |
33 | (defcustom treesit-fold-summary-show t
34 | "Flag to show summary if available."
35 | :type 'boolean
36 | :group 'treesit-fold)
37 |
38 | (defcustom treesit-fold-summary-max-length 60
39 | "Maximum length for summary to display."
40 | :type '(choice (const :tag "nil" nil)
41 | (integer :tag "positive integer number"))
42 | :group 'treesit-fold)
43 |
44 | (defcustom treesit-fold-summary-format " %s "
45 | "Prefix string added before summary overlay."
46 | :type 'string
47 | :group 'treesit-fold)
48 |
49 | ;;
50 | ;; (@* "Externals" )
51 | ;;
52 |
53 | (defvar treesit-fold-replacement-face)
54 |
55 | ;;
56 | ;; (@* "Parsers" )
57 | ;;
58 |
59 | (defun treesit-fold-summary--valid-content-p (content)
60 | "Return non-nil if CONTENT is a valid document string for extraction.
61 | Some programmers use some type of characters for splitting the code module
62 | into sections. For instance, ===, ---, ///, =-=, etc. Try to omit these
63 | type of content by checking the word boundary's existence."
64 | (string-match-p "\\w" content))
65 |
66 | (defun treesit-fold-summary--apply-sym (line sym)
67 | "Remove SYM from LINE."
68 | (when (string-prefix-p sym line)
69 | (setq line (substring line (length sym) (length line))
70 | line (string-trim line)))
71 | line)
72 |
73 | (defun treesit-fold-summary--extract-summary (doc-str sym)
74 | "Extract only document summary from DOC-STR using SYM."
75 | (let ((lines (split-string doc-str "\n")) new-lines)
76 | (dolist (line lines)
77 | (setq line (string-trim line))
78 | (cond ((listp sym)
79 | (dolist (c sym) (setq line (treesit-fold-summary--apply-sym line c))))
80 | (t (setq line (treesit-fold-summary--apply-sym line sym))))
81 | (when (treesit-fold-summary--valid-content-p line) (push line new-lines)))
82 | (reverse new-lines)))
83 |
84 | (defun treesit-fold-summary--doc-extract (doc-str sym)
85 | "Default way to extract the doc summary from DOC-STR using SYM."
86 | (let* ((lines (treesit-fold-summary--extract-summary doc-str sym)) (summary (nth 0 lines)))
87 | (when summary (setq summary (string-trim summary)))
88 | (if (string-empty-p summary) nil summary)))
89 |
90 | (defun treesit-fold-summary--generic (doc-str sym)
91 | "Generic DOC-STR extraction using SYM."
92 | (when (treesit-fold--doc-faces-p doc-str)
93 | (treesit-fold-summary--doc-extract doc-str sym)))
94 |
95 | (defun treesit-fold-summary-batch (doc-str)
96 | "Extract summary from DOC-STR in Batch."
97 | (treesit-fold-summary--generic doc-str '("::" "rem" "REM")))
98 |
99 | (defun treesit-fold-summary-csharp-vsdoc (doc-str)
100 | "Extract summary from DOC-STR in C# vsdoc."
101 | (let ((type-triple (string-match-p "///" doc-str)))
102 | (setq doc-str (replace-regexp-in-string "<[/]*[^>]+." "" doc-str))
103 | (treesit-fold-summary--generic doc-str (if type-triple "///" "//"))))
104 |
105 | (defun treesit-fold-summary-csharp (doc-str)
106 | "Extract summary from DOC-STR in C#."
107 | (cond ((string-match-p "///" doc-str)
108 | (treesit-fold-summary-csharp-vsdoc doc-str))
109 | (t (treesit-fold-summary-javadoc doc-str))))
110 |
111 | (defun treesit-fold-summary-elisp (doc-str)
112 | "Extract summary from DOC-STR in Elisp."
113 | (treesit-fold-summary--generic doc-str ";;"))
114 |
115 | (defun treesit-fold-summary-javadoc (doc-str)
116 | "Extract summary from DOC-STR in Javadoc."
117 | (treesit-fold-summary--generic doc-str "*"))
118 |
119 | (defun treesit-fold-summary-go (doc-str)
120 | "Extract summary from DOC-STR in Go."
121 | (treesit-fold-summary--generic doc-str "//"))
122 |
123 | (defun treesit-fold-summary-lua-doc (doc-str)
124 | "Extract summary from DOC-STR in Lua."
125 | (treesit-fold-summary--generic doc-str "--"))
126 |
127 | (defun treesit-fold-summary-pascal-doc (doc-str)
128 | "Extract summary from DOC-STR in Pascal."
129 | (cond ((string-prefix-p "{" doc-str)
130 | (treesit-fold-summary--generic doc-str '("{" "}")))
131 | (t (treesit-fold-summary-go doc-str))))
132 |
133 | (defun treesit-fold-summary-python-doc (doc-str)
134 | "Extract summary from DOC-STR in Python."
135 | (treesit-fold-summary--generic doc-str "\"\"\""))
136 |
137 | (defun treesit-fold-summary-rst-doc (doc-str)
138 | "Extract summary from DOC-STR in reStructuredText."
139 | (treesit-fold-summary--generic doc-str ".."))
140 |
141 | (defun treesit-fold-summary-ruby-doc (doc-str)
142 | "Extract summary from DOC-STR in Ruby."
143 | (treesit-fold-summary--generic doc-str "#"))
144 |
145 | (defun treesit-fold-summary-rust-doc (doc-str)
146 | "Extract summary from DOC-STR in Rust."
147 | (treesit-fold-summary--generic doc-str "///"))
148 |
149 | (defun treesit-fold-summary-tex-doc (doc-str)
150 | "Extract summary from DOC-STR in Tex family."
151 | (treesit-fold-summary--generic doc-str "%"))
152 |
153 | (defun treesit-fold-summary-c-macro (doc-str)
154 | "Parse C macro summary from DOC-STR."
155 | (when (treesit-fold--is-face doc-str
156 | '( font-lock-preprocessor-face
157 | preproc-font-lock-preprocessor-background))
158 | (treesit-fold-summary--doc-extract doc-str "")))
159 |
160 | (defun treesit-fold-summary-c (doc-str)
161 | "Extract summary from DOC-STR in C comment."
162 | (or (treesit-fold-summary-javadoc doc-str)
163 | (treesit-fold-summary-c-macro doc-str)))
164 |
165 | (defun treesit-fold-summary-markdown (doc-str)
166 | "Extract summary from DOC-STR in Markdown block."
167 | (treesit-fold-summary--doc-extract doc-str '("-" "```")))
168 |
169 | (defun treesit-fold-summary-matlab-doc (doc-str)
170 | "Extract summary from MATLAB DOC-STR."
171 | (treesit-fold-summary--generic doc-str "%"))
172 |
173 | (defun treesit-fold-summary-mermaid (doc-str)
174 | "Extract summary from DOC-STR in Mermaid comment."
175 | (treesit-fold-summary--generic doc-str '("%%")))
176 |
177 | (defun treesit-fold-summary-org (doc-str)
178 | "Extract summary from DOC-STR in Org block."
179 | (treesit-fold-summary--doc-extract doc-str '()))
180 |
181 | (defun treesit-fold-summary-xml (doc-str)
182 | "Extract summary from DOC-STR in XML."
183 | (treesit-fold-summary--generic doc-str "-"))
184 |
185 | (defun treesit-fold-summary-julia-doc (doc-str)
186 | "Extract summary from DOC-STR in Julia."
187 | (treesit-fold-summary--generic doc-str '("#" "\"\"\"")))
188 |
189 | ;;
190 | ;; (@* "Core" )
191 | ;;
192 |
193 | ;; TODO(everyone): keep this alist alphabetically sorted
194 | (defcustom treesit-fold-summary-parsers-alist
195 | `((actionscript-mode . treesit-fold-summary-javadoc)
196 | (arduino-mode . treesit-fold-summary-c)
197 | (asm-mode . treesit-fold-summary-elisp)
198 | (fasm-mode . treesit-fold-summary-elisp)
199 | (masm-mode . treesit-fold-summary-elisp)
200 | (nasm-mode . treesit-fold-summary-elisp)
201 | (gas-mode . treesit-fold-summary-elisp)
202 | (bat-mode . treesit-fold-summary-batch)
203 | (beancount-mode . treesit-fold-summary-elisp)
204 | (c-mode . treesit-fold-summary-c)
205 | (c++-mode . treesit-fold-summary-c)
206 | (cmake-mode . treesit-fold-summary-ruby-doc)
207 | (clojure-mode . treesit-fold-summary-elisp)
208 | (csharp-mode . treesit-fold-summary-csharp)
209 | (css-mode . treesit-fold-summary-javadoc)
210 | (dart-mode . treesit-fold-summary-javadoc)
211 | (editorconfig-conf-mode . treesit-fold-summary-ruby-doc)
212 | (emacs-lisp-mode . treesit-fold-summary-elisp)
213 | (elixir-mode . treesit-fold-summary-ruby-doc)
214 | (erlang-mode . treesit-fold-summary-tex-doc)
215 | (fish-mode . treesit-fold-summary-javadoc)
216 | (gdscript-mode . treesit-fold-summary-ruby-doc)
217 | (glsl-mode . treesit-fold-summary-c)
218 | (go-mode . treesit-fold-summary-go)
219 | (groovy-mode . treesit-fold-summary-javadoc)
220 | (jenkinsfile-mode . treesit-fold-summary-javadoc)
221 | (haskell-mode . treesit-fold-summary-lua-doc)
222 | (haxe-mode . treesit-fold-summary-javadoc)
223 | (heex-mode . treesit-fold-summary-xml)
224 | (hlsl-mode . treesit-fold-summary-c)
225 | (html-mode . treesit-fold-summary-xml)
226 | (jai-mode . treesit-fold-summary-c)
227 | (janet-mode . treesit-fold-summary-ruby-doc)
228 | (java-mode . treesit-fold-summary-javadoc)
229 | (javascript-mode . treesit-fold-summary-javadoc)
230 | (js-mode . treesit-fold-summary-javadoc)
231 | (js2-mode . treesit-fold-summary-javadoc)
232 | (js3-mode . treesit-fold-summary-javadoc)
233 | (json-mode . treesit-fold-summary-javadoc)
234 | (jsonnet-mode . treesit-fold-summary-javadoc)
235 | (julia-mode . treesit-fold-summary-julia-doc)
236 | (kotlin-mode . treesit-fold-summary-javadoc)
237 | (latex-mode . treesit-fold-summary-tex-doc)
238 | (LaTeX-mode . treesit-fold-summary-tex-doc)
239 | (lisp-mode . treesit-fold-summary-elisp)
240 | (lisp-interaction-mode . treesit-fold-summary-elisp)
241 | (llvm-mode . treesit-fold-summary-elisp)
242 | (llvm-mir-mode . treesit-fold-summary-elisp)
243 | (lua-mode . treesit-fold-summary-lua-doc)
244 | (magik-mode . treesit-fold-summary-ruby-doc)
245 | (makefile-mode . treesit-fold-summary-ruby-doc)
246 | (makefile-automake-mode . treesit-fold-summary-ruby-doc)
247 | (makefile-gmake-mode . treesit-fold-summary-ruby-doc)
248 | (makefile-makepp-mode . treesit-fold-summary-ruby-doc)
249 | (makefile-bsdmake-mode . treesit-fold-summary-ruby-doc)
250 | (makefile-imake-mode . treesit-fold-summary-ruby-doc)
251 | (markdown-mode . treesit-fold-summary-markdown)
252 | (matlab-mode . treesit-fold-summary-matlab-doc)
253 | (mermaid-mode . treesit-fold-summary-mermaid)
254 | (ninja-mode . treesit-fold-summary-ruby-doc)
255 | (nix-mode . treesit-fold-summary-ruby-doc)
256 | (noir-mode . treesit-fold-summary-rust-doc)
257 | (objc-mode . treesit-fold-summary-c)
258 | (org-mode . treesit-fold-summary-org)
259 | (perl-mode . treesit-fold-summary-ruby-doc)
260 | (php-mode . treesit-fold-summary-javadoc)
261 | (pascal-mode . treesit-fold-summary-pascal-doc)
262 | (python-mode . treesit-fold-summary-python-doc)
263 | (qss-mode . treesit-fold-summary-css)
264 | (rjsx-mode . treesit-fold-summary-javadoc)
265 | (rst-mode . treesit-fold-summary-rst-doc)
266 | (ruby-mode . treesit-fold-summary-ruby-doc)
267 | (rust-mode . treesit-fold-summary-rust-doc)
268 | (scala-mode . treesit-fold-summary-javadoc)
269 | (scheme-mode . treesit-fold-summary-elisp)
270 | (sh-mode . treesit-fold-summary-javadoc)
271 | (sql-mode . treesit-fold-summary-c)
272 | (svelte-mode . treesit-fold-summary-xml)
273 | (swift-mode . treesit-fold-summary-c)
274 | (tablegen-mode . treesit-fold-summary-javadoc)
275 | (toml-mode . treesit-fold-summary-javadoc)
276 | (conf-toml-mode . treesit-fold-summary-javadoc)
277 | (typescript-mode . treesit-fold-summary-javadoc)
278 | (verilog-mode . treesit-fold-summary-javadoc)
279 | (vhdl-mode . treesit-fold-summary-lua-doc)
280 | (nxml-mode . treesit-fold-summary-xml)
281 | (yaml-mode . treesit-fold-summary-ruby-doc)
282 | (k8s-mode . treesit-fold-summary-ruby-doc)
283 | (zig-mode . treesit-fold-summary-go))
284 | "Alist mapping `major-mode' to doc parser function."
285 | :type '(alist :key-type symbol :value-type function)
286 | :group 'treesit-fold)
287 |
288 | (defun treesit-fold-summary--keep-length (summary)
289 | "Keep the SUMMARY length to `treesit-fold-summary-max-length'."
290 | (let ((len-sum (length summary)))
291 | (when (< treesit-fold-summary-max-length len-sum)
292 | (setq summary (truncate-string-to-width summary
293 | treesit-fold-summary-max-length
294 | 0 nil
295 | t))))
296 | summary)
297 |
298 | (defun treesit-fold-summary--apply-format (summary)
299 | "Return the SUMMARY that has added the summary prefix."
300 | (format treesit-fold-summary-format summary))
301 |
302 | (defun treesit-fold-summary--parser ()
303 | "Return the summary parser from `treesit-fold-summary-parsers-alist'."
304 | (assoc (buffer-local-value 'major-mode (current-buffer)) treesit-fold-summary-parsers-alist))
305 |
306 | (defun treesit-fold-summary--get (doc-str)
307 | "Extract summary from DOC-STR in order to display ontop of the overlay."
308 | (let ((parser (cdr (treesit-fold-summary--parser))) summary
309 | (map (make-sparse-keymap)))
310 | (keymap-set map "" #'treesit-fold-open)
311 | (when parser
312 | (setq summary (funcall parser doc-str))
313 | (when (integerp treesit-fold-summary-max-length)
314 | (setq summary (treesit-fold-summary--keep-length summary)))
315 | (when summary
316 | (setq summary (treesit-fold-summary--apply-format summary)
317 | summary (propertize summary 'face 'treesit-fold-replacement-face
318 | 'mouse-face 'treesit-fold-replacement-mouse-face
319 | 'keymap map))))
320 | summary))
321 |
322 | (provide 'treesit-fold-summary)
323 | ;;; treesit-fold-summary.el ends here
324 |
--------------------------------------------------------------------------------
/treesit-fold-util.el:
--------------------------------------------------------------------------------
1 | ;;; treesit-fold-util.el --- Utility module -*- lexical-binding: t; -*-
2 |
3 | ;; Copyright (C) 2021-2025 emacs-tree-sitter maintainers
4 |
5 | ;; Created date 2021-10-04 20:19:42
6 |
7 | ;; This file is NOT part of GNU Emacs.
8 |
9 | ;; This program is free software; you can redistribute it and/or modify
10 | ;; it under the terms of the GNU General Public License as published by
11 | ;; the Free Software Foundation, either version 3 of the License, or
12 | ;; (at your option) any later version.
13 |
14 | ;; This program is distributed in the hope that it will be useful,
15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | ;; GNU General Public License for more details.
18 |
19 | ;; You should have received a copy of the GNU General Public License
20 | ;; along with this program. If not, see .
21 |
22 | ;;; Commentary:
23 | ;;
24 | ;; Utility module.
25 | ;;
26 |
27 | ;;; Code:
28 |
29 | ;;
30 | ;; (@* "Redisplay" )
31 | ;;
32 |
33 | (defmacro treesit-fold--with-no-redisplay (&rest body)
34 | "Execute BODY without any redisplay execution."
35 | (declare (indent 0) (debug t))
36 | `(let ((inhibit-redisplay t)
37 | (inhibit-modification-hooks t)
38 | after-focus-change-function
39 | buffer-list-update-hook
40 | display-buffer-alist
41 | window-configuration-change-hook
42 | window-scroll-functions
43 | window-size-change-functions
44 | window-state-change-hook
45 | jit-lock-mode)
46 | ,@body))
47 |
48 | ;;
49 | ;; (@* "String" )
50 | ;;
51 |
52 | (defun treesit-fold-2str (obj)
53 | "Convert OBJ to string."
54 | (format "%s" obj))
55 |
56 | (defun treesit-fold--count-matches (pattern str)
57 | "Count occurrences of PATTERN in STR.
58 |
59 | Like function `s-count-matches' but faster."
60 | (max 0 (1- (length (split-string str pattern)))))
61 |
62 | ;;
63 | ;; (@* "Cons" )
64 | ;;
65 |
66 | (defun treesit-fold--cons-add (&rest args)
67 | "Addition for list of cons ARGS."
68 | (let ((v1 0) (v2 0))
69 | (dolist (c args)
70 | (setq v1 (+ v1 (car c))
71 | v2 (+ v2 (cdr c))))
72 | (cons v1 v2)))
73 |
74 | ;;
75 | ;; (@* "Overlay" )
76 | ;;
77 |
78 | (defun treesit-fold--overlays-in (prop name &optional beg end)
79 | "Return overlays with PROP of NAME, from region BEG to END."
80 | (unless beg (setq beg (point-min))) (unless end (setq end (point-max)))
81 | (let ((lst '()) (ovs (overlays-in beg end)))
82 | (dolist (ov ovs)
83 | (when (eq name (overlay-get ov prop))
84 | (push ov lst)))
85 | lst))
86 |
87 | ;;
88 | ;; (@* "Face" )
89 | ;;
90 |
91 | (defvar treesit-fold--doc-faces
92 | '( font-lock-doc-face
93 | font-lock-comment-face
94 | font-lock-comment-delimiter-face
95 | tree-sitter-hl-face:comment
96 | tree-sitter-hl-face:doc
97 | hl-todo
98 | rst-comment)
99 | "List of face that apply for document string.")
100 |
101 | (defun treesit-fold--get-face (obj trim)
102 | "Return face name from OBJ.
103 | If argument TRIM is non-nil, trim the OBJ."
104 | (let* ((obj (if trim (string-trim obj) obj))
105 | (len (length obj)))
106 | (or (get-text-property 0 'face obj)
107 | (and (<= 1 len)
108 | (get-text-property 1 'face obj)))))
109 |
110 | (defun treesit-fold--is-face (obj lst-face &optional trim)
111 | "Return non-nil if OBJ's face is define inside list LST-FACE.
112 | Optional argument TRIM, see function `treesit-fold--get-face'."
113 | (unless (listp lst-face) (setq lst-face (list lst-face)))
114 | (let ((faces (treesit-fold--get-face obj trim)))
115 | (cond ((listp faces)
116 | (cl-some (lambda (face) (memq face lst-face)) faces))
117 | (t (memq faces lst-face)))))
118 |
119 | (defun treesit-fold--doc-faces-p (obj &optional trim)
120 | "Return non-nil if face at OBJ is within `treesit-fold--doc-faces' list.
121 | Optional argument TRIM, see function `treesit-fold--get-face'."
122 | (treesit-fold--is-face obj treesit-fold--doc-faces trim))
123 |
124 | ;;
125 | ;; (@* "Positions" )
126 | ;;
127 |
128 | (defun treesit-fold--last-eol (pos)
129 | "Go to POS then find previous line break, and return its position."
130 | (save-excursion
131 | (goto-char pos)
132 | (max 1 (1- (line-beginning-position)))))
133 |
134 | (defun treesit-fold--bol (point)
135 | "Return line beginning position at POINT."
136 | (save-excursion (goto-char point) (line-beginning-position)))
137 |
138 | (defun treesit-fold--eol (point)
139 | "Return line end position at POINT."
140 | (save-excursion (goto-char point) (line-end-position)))
141 |
142 | (defun treesit-fold--indentation (pos)
143 | "Return current indentation by POS."
144 | (goto-char pos)
145 | (current-indentation))
146 |
147 | (defun treesit-fold--node-start-point (node)
148 | "Return NODE's start point."
149 | (save-excursion
150 | (goto-char (treesit-node-start node))
151 | (cons (line-number-at-pos) (current-column))))
152 |
153 | (defun treesit-fold--node-end-point (node)
154 | "Return NODE's end point."
155 | (save-excursion
156 | (goto-char (treesit-node-end node))
157 | (cons (line-number-at-pos) (current-column))))
158 |
159 | ;;
160 | ;; (@* "Math" )
161 | ;;
162 |
163 | (defun treesit-fold--in-range-p (in-val in-min in-max)
164 | "Check to see if IN-VAL is between IN-MIN and IN-MAX."
165 | (and (<= in-min in-val) (<= in-val in-max)))
166 |
167 | ;;
168 | ;; (@* "List" )
169 | ;;
170 |
171 | (defun treesit-fold-listify (obj)
172 | "Ensure OBJ is a list."
173 | (if (listp obj) obj (list obj)))
174 |
175 | ;;
176 | ;; (@* "Window" )
177 | ;;
178 |
179 | (defmacro treesit-fold--with-selected-window (window &rest body)
180 | "Same with `with-selected-window' but safe.
181 |
182 | See macro `with-selected-window' description for arguments WINDOW and BODY."
183 | (declare (indent 1) (debug t))
184 | `(when (window-live-p ,window) (with-selected-window ,window ,@body)))
185 |
186 | ;;
187 | ;; (@* "TS node" )
188 | ;;
189 |
190 | (defun treesit-fold--compare-type (node type)
191 | "Compare NODE's type to TYPE."
192 | (string= (treesit-node-type node) type))
193 |
194 | (defun treesit-fold-find-children (node type)
195 | "Search through the children of NODE to find all with type equal to TYPE;
196 | then return that list."
197 | (cl-remove-if-not (lambda (child) (treesit-fold--compare-type child type))
198 | (treesit-node-children node)))
199 |
200 | (defun treesit-fold-find-parent (node type)
201 | "Find the TYPE of parent from NODE."
202 | (let ((parent (treesit-node-parent node))
203 | (break))
204 | (while (and parent (not break))
205 | (setq break (treesit-fold--compare-type parent type))
206 | (unless break
207 | (setq parent (treesit-node-parent parent))))
208 | parent))
209 |
210 | (defun treesit-fold-last-child (node)
211 | "Return last child node from parent NODE."
212 | (when-let* ((count (treesit-node-child-count node))
213 | ((not (= count 0))))
214 | (treesit-node-child node (1- count))))
215 |
216 | (provide 'treesit-fold-util)
217 | ;;; treesit-fold-util.el ends here
218 |
--------------------------------------------------------------------------------
/treesit-fold.el:
--------------------------------------------------------------------------------
1 | ;;; treesit-fold.el --- Code folding using treesit -*- lexical-binding: t; -*-
2 |
3 | ;; Copyright (C) 2021-2025 emacs-tree-sitter maintainers
4 |
5 | ;; Created date 2021-08-11 14:12:37
6 |
7 | ;; Author: Junyi Hou
8 | ;; Shen, Jen-Chieh
9 | ;; Maintainer: Shen, Jen-Chieh
10 | ;; URL: https://github.com/emacs-tree-sitter/treesit-fold
11 | ;; Version: 0.2.1
12 | ;; Package-Requires: ((emacs "29.1"))
13 | ;; Keywords: convenience folding tree-sitter
14 |
15 | ;; This file is NOT part of GNU Emacs.
16 |
17 | ;; This program is free software; you can redistribute it and/or modify
18 | ;; it under the terms of the GNU General Public License as published by
19 | ;; the Free Software Foundation, either version 3 of the License, or
20 | ;; (at your option) any later version.
21 |
22 | ;; This program is distributed in the hope that it will be useful,
23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 | ;; GNU General Public License for more details.
26 |
27 | ;; You should have received a copy of the GNU General Public License
28 | ;; along with this program. If not, see .
29 |
30 | ;;; Commentary:
31 | ;;
32 | ;; This package provides a code-folding mechanism based on tree-sitter
33 | ;; package. Turn on the minor-mode `treesit-fold-mode' to enable
34 | ;; this mechanism. Note that all functionalities provided here based on the
35 | ;; `tree-sitter-mode', and thus it should be enabled before
36 | ;; `treesit-fold-mode' can properly fold codes.
37 |
38 | ;;; Code:
39 |
40 | (require 'mule-util)
41 | (require 'seq)
42 | (require 'subr-x)
43 |
44 | (require 'treesit)
45 |
46 | (require 'treesit-fold-util)
47 | (require 'treesit-fold-parsers)
48 | (require 'treesit-fold-summary)
49 |
50 | ;;
51 | ;; (@* "Customization" )
52 | ;;
53 |
54 | (defgroup treesit-fold nil
55 | "Code folding using tree-sitter."
56 | :group 'tree-sitter
57 | :prefix "treesit-fold-")
58 |
59 | ;; TODO(everyone): This is a bit messy, but try to keep this alist
60 | ;; alphabetically sorted
61 | (defcustom treesit-fold-range-alist
62 | `((actionscript-mode . ,(treesit-fold-parsers-actionscript))
63 | (agda-mode . ,(treesit-fold-parsers-agda))
64 | (arduino-mode . ,(treesit-fold-parsers-arduino))
65 | (asm-mode . ,(treesit-fold-parsers-asm))
66 | (awk-mode . ,(treesit-fold-parsers-awk))
67 | (awk-ts-mode . ,(treesit-fold-parsers-awk))
68 | (editorconfig-conf-mode . ,(treesit-fold-parsers-editorconfig))
69 | (fasm-mode . ,(treesit-fold-parsers-asm))
70 | (masm-mode . ,(treesit-fold-parsers-asm))
71 | (nasm-mode . ,(treesit-fold-parsers-asm))
72 | (gas-mode . ,(treesit-fold-parsers-asm))
73 | (bash-ts-mode . ,(treesit-fold-parsers-bash))
74 | (beancount-mode . ,(treesit-fold-parsers-beancount))
75 | (beancount-ts-mode . ,(treesit-fold-parsers-beancount))
76 | (c-mode . ,(treesit-fold-parsers-c))
77 | (c-ts-mode . ,(treesit-fold-parsers-c))
78 | (c++-mode . ,(treesit-fold-parsers-c++))
79 | (c++-ts-mode . ,(treesit-fold-parsers-c++))
80 | (caml-mode . ,(treesit-fold-parsers-ocaml))
81 | (caml-ts-mode . ,(treesit-fold-parsers-ocaml))
82 | (cmake-mode . ,(treesit-fold-parsers-cmake))
83 | (cmake-ts-mode . ,(treesit-fold-parsers-cmake))
84 | (clojure-mode . ,(treesit-fold-parsers-clojure))
85 | (clojure-ts-mode . ,(treesit-fold-parsers-clojure))
86 | (csharp-mode . ,(treesit-fold-parsers-csharp))
87 | (csharp-ts-mode . ,(treesit-fold-parsers-csharp))
88 | (css-mode . ,(treesit-fold-parsers-css))
89 | (css-ts-mode . ,(treesit-fold-parsers-css))
90 | (dart-mode . ,(treesit-fold-parsers-dart))
91 | (dart-ts-mode . ,(treesit-fold-parsers-dart))
92 | (emacs-lisp-mode . ,(treesit-fold-parsers-elisp))
93 | (elixir-mode . ,(treesit-fold-parsers-elixir))
94 | (elixir-ts-mode . ,(treesit-fold-parsers-elixir))
95 | (erlang-mode . ,(treesit-fold-parsers-erlang))
96 | (erlang-ts-mode . ,(treesit-fold-parsers-erlang))
97 | (ess-r-mode . ,(treesit-fold-parsers-r))
98 | (fish-mode . ,(treesit-fold-parsers-fish))
99 | (gdscript-mode . ,(treesit-fold-parsers-gdscript))
100 | (gdscript-ts-mode . ,(treesit-fold-parsers-gdscript))
101 | (gleam-ts-mode . ,(treesit-fold-parsers-gleam))
102 | (glsl-mode . ,(treesit-fold-parsers-glsl))
103 | (go-mode . ,(treesit-fold-parsers-go))
104 | (go-ts-mode . ,(treesit-fold-parsers-go))
105 | (go-mod-ts-mode . ,(treesit-fold-parsers-go))
106 | (groovy-mode . ,(treesit-fold-parsers-groovy))
107 | (jenkinsfile-mode . ,(treesit-fold-parsers-groovy))
108 | (haskell-mode . ,(treesit-fold-parsers-haskell))
109 | (haskell-ts-mode . ,(treesit-fold-parsers-haskell))
110 | (haxe-mode . ,(treesit-fold-parsers-haxe))
111 | (heex-mode . ,(treesit-fold-parsers-heex))
112 | (heex-ts-mode . ,(treesit-fold-parsers-heex))
113 | (hlsl-mode . ,(treesit-fold-parsers-hlsl))
114 | (hlsl-ts-mode . ,(treesit-fold-parsers-hlsl))
115 | (html-mode . ,(treesit-fold-parsers-html))
116 | (html-ts-mode . ,(treesit-fold-parsers-html))
117 | (jai-mode . ,(treesit-fold-parsers-jai))
118 | (janet-mode . ,(treesit-fold-parsers-janet))
119 | (java-mode . ,(treesit-fold-parsers-java))
120 | (java-ts-mode . ,(treesit-fold-parsers-java))
121 | (javascript-mode . ,(treesit-fold-parsers-javascript))
122 | (js-mode . ,(treesit-fold-parsers-javascript))
123 | (js-ts-mode . ,(treesit-fold-parsers-javascript))
124 | (js2-mode . ,(treesit-fold-parsers-javascript))
125 | (js3-mode . ,(treesit-fold-parsers-javascript))
126 | (json-mode . ,(treesit-fold-parsers-json))
127 | (json-ts-mode . ,(treesit-fold-parsers-json))
128 | (jsonc-mode . ,(treesit-fold-parsers-json))
129 | (jsonnet-mode . ,(treesit-fold-parsers-jsonnet))
130 | (julia-mode . ,(treesit-fold-parsers-julia))
131 | (julia-ts-mode . ,(treesit-fold-parsers-julia))
132 | (kotlin-mode . ,(treesit-fold-parsers-kotlin))
133 | (kotlin-ts-mode . ,(treesit-fold-parsers-kotlin))
134 | (latex-mode . ,(treesit-fold-parsers-latex))
135 | (latex-ts-mode . ,(treesit-fold-parsers-latex))
136 | (LaTeX-mode . ,(treesit-fold-parsers-latex))
137 | (lisp-mode . ,(treesit-fold-parsers-lisp))
138 | (lisp-interaction-mode . ,(treesit-fold-parsers-lisp))
139 | (llvm-mode . ,(treesit-fold-parsers-llvm))
140 | (llvm-mir-mode . ,(treesit-fold-parsers-llvm-mir))
141 | (lua-mode . ,(treesit-fold-parsers-lua))
142 | (lua-ts-mode . ,(treesit-fold-parsers-lua))
143 | (magik-mode . ,(treesit-fold-parsers-magik))
144 | (magik-ts-mode . ,(treesit-fold-parsers-magik))
145 | (makefile-mode . ,(treesit-fold-parsers-make))
146 | (makefile-ts-mode . ,(treesit-fold-parsers-make))
147 | (makefile-automake-mode . ,(treesit-fold-parsers-make))
148 | (makefile-gmake-mode . ,(treesit-fold-parsers-make))
149 | (makefile-makepp-mode . ,(treesit-fold-parsers-make))
150 | (makefile-bsdmake-mode . ,(treesit-fold-parsers-make))
151 | (makefile-imake-mode . ,(treesit-fold-parsers-make))
152 | (markdown-mode . ,(treesit-fold-parsers-markdown))
153 | (markdown-ts-mode . ,(treesit-fold-parsers-markdown))
154 | (matlab-mode . ,(treesit-fold-parsers-matlab))
155 | (mermaid-mode . ,(treesit-fold-parsers-mermaid))
156 | (mermaid-ts-mode . ,(treesit-fold-parsers-mermaid))
157 | (ninja-mode . ,(treesit-fold-parsers-ninja))
158 | (noir-mode . ,(treesit-fold-parsers-noir))
159 | (noir-ts-mode . ,(treesit-fold-parsers-noir))
160 | (nix-mode . ,(treesit-fold-parsers-nix))
161 | (nix-ts-mode . ,(treesit-fold-parsers-nix))
162 | (ocaml-mode . ,(treesit-fold-parsers-ocaml))
163 | (ocaml-ts-mode . ,(treesit-fold-parsers-ocaml))
164 | (org-mode . ,(treesit-fold-parsers-org))
165 | (pascal-mode . ,(treesit-fold-parsers-pascal))
166 | (perl-mode . ,(treesit-fold-parsers-perl))
167 | (php-mode . ,(treesit-fold-parsers-php))
168 | (php-ts-mode . ,(treesit-fold-parsers-php))
169 | (python-mode . ,(treesit-fold-parsers-python))
170 | (python-ts-mode . ,(treesit-fold-parsers-python))
171 | (qss-mode . ,(treesit-fold-parsers-qss))
172 | (rjsx-mode . ,(treesit-fold-parsers-javascript))
173 | (rst-mode . ,(treesit-fold-parsers-rst))
174 | (ruby-mode . ,(treesit-fold-parsers-ruby))
175 | (ruby-ts-mode . ,(treesit-fold-parsers-ruby))
176 | (rust-mode . ,(treesit-fold-parsers-rust))
177 | (rust-ts-mode . ,(treesit-fold-parsers-rust))
178 | (rustic-mode . ,(treesit-fold-parsers-rust))
179 | (scheme-mode . ,(treesit-fold-parsers-scheme))
180 | (sh-mode . ,(treesit-fold-parsers-bash))
181 | (scala-mode . ,(treesit-fold-parsers-scala))
182 | (scala-ts-mode . ,(treesit-fold-parsers-scala))
183 | (sql-mode . ,(treesit-fold-parsers-sql))
184 | (svelte-mode . ,(treesit-fold-parsers-svelte))
185 | (swift-mode . ,(treesit-fold-parsers-swift))
186 | (tablegen-mode . ,(treesit-fold-parsers-tablegen))
187 | (toml-mode . ,(treesit-fold-parsers-toml))
188 | (toml-ts-mode . ,(treesit-fold-parsers-toml))
189 | (conf-toml-mode . ,(treesit-fold-parsers-toml))
190 | (tuareg-mode . ,(treesit-fold-parsers-ocaml))
191 | (typescript-mode . ,(treesit-fold-parsers-typescript))
192 | (typescript-ts-mode . ,(treesit-fold-parsers-typescript))
193 | (tsx-ts-mode . ,(treesit-fold-parsers-typescript))
194 | (verilog-mode . ,(treesit-fold-parsers-verilog))
195 | (verilog-ts-mode . ,(treesit-fold-parsers-verilog))
196 | (vhdl-mode . ,(treesit-fold-parsers-vhdl))
197 | (vhdl-ts-mode . ,(treesit-fold-parsers-vhdl))
198 | (vimscript-ts-mode . ,(treesit-fold-parsers-vimscript))
199 | (nxml-mode . ,(treesit-fold-parsers-xml))
200 | (xml-ts-mode . ,(treesit-fold-parsers-xml))
201 | (yaml-mode . ,(treesit-fold-parsers-yaml))
202 | (yaml-ts-mode . ,(treesit-fold-parsers-yaml))
203 | (k8s-mode . ,(treesit-fold-parsers-yaml))
204 | (zig-mode . ,(treesit-fold-parsers-zig)))
205 | "An alist of (major-mode . (foldable-node-type . function)).
206 |
207 | FUNCTION is used to determine where the beginning and end for FOLDABLE-NODE-TYPE
208 | in MAJOR-MODE. It should take a single argument (the syntax node with type
209 | FOLDABLE-NODE-TYPE) and return the buffer positions of the beginning and end of
210 | the fold in a cons cell. See `treesit-fold-range-python-def' for an example."
211 | :type '(alist :key-type symbol
212 | :value-type (alist :key-type symbol :value-type function))
213 | :group 'treesit-fold)
214 |
215 | (defcustom treesit-fold-mode-hook nil
216 | "Hook to run when enabling `treesit-fold-mode`."
217 | :type 'hook
218 | :group 'treesit-fold)
219 |
220 | (defcustom treesit-fold-on-fold-hook nil
221 | "Hook runs on folding."
222 | :type 'hook
223 | :group 'treesit-fold)
224 |
225 | (defcustom treesit-fold-on-next-line t
226 | "If non-nil, we leave ending keywords on the next line.
227 |
228 | This is only used in languages that uses keyword to end the scope.
229 | For example, Lua, Ruby, etc."
230 | :type 'boolean
231 | :group 'treesit-fold)
232 |
233 | (defcustom treesit-fold-priority 30
234 | "Fold range overlay's priority."
235 | :type 'integer
236 | :group 'treesit-fold)
237 |
238 | (defface treesit-fold-replacement-face
239 | '((t :foreground "#808080" :box (:line-width -1 :style pressed-button)))
240 | "Face used to display the fold replacement text."
241 | :group 'treesit-fold)
242 |
243 | (defface treesit-fold-replacement-mouse-face
244 | '((t :foreground "#808080" :box (:line-width -1 :style released-button)))
245 | "Face used to when mouse hovering replacement text."
246 | :group 'treesit-fold)
247 |
248 | (defface treesit-fold-fringe-face
249 | '((t ()))
250 | "Face used to display fringe contents."
251 | :group 'treesit-fold)
252 |
253 | (defcustom treesit-fold-line-count-show nil
254 | "Show the number of lines in folded text."
255 | :type 'boolean
256 | :group 'treesit-fold)
257 |
258 | (defcustom treesit-fold-line-count-format
259 | (concat (truncate-string-ellipsis)
260 | " %d "
261 | (truncate-string-ellipsis))
262 | "Format string for displaying line count in folded text.
263 |
264 | The %d will be replaced with the number of lines in the folded region."
265 | :type 'string
266 | :group 'treesit-fold)
267 |
268 | ;;
269 | ;; (@* "Externals" )
270 | ;;
271 |
272 | (defvar treesit-fold-indicators-mode)
273 |
274 | (declare-function treesit-fold-indicators-mode "treesit-fold-indicators.el")
275 | (declare-function treesit-fold-indicators-refresh "treesit-fold-indicators.el")
276 |
277 | (defun treesit-fold--indicators-refresh ()
278 | "Safe version of the `treesit-fold-indicators-refresh' function."
279 | (when (bound-and-true-p treesit-fold-indicators-mode)
280 | (treesit-fold-indicators-refresh)))
281 |
282 | ;;
283 | ;; (@* "Entry" )
284 | ;;
285 |
286 | (defvar-keymap treesit-fold-mode-map
287 | :doc "Keymap used when `treesit-fold-mode' is active.")
288 |
289 | (defun treesit-fold--enable ()
290 | "Start folding minor mode."
291 | (setq-local line-move-ignore-invisible t)
292 | (add-to-invisibility-spec '(treesit-fold . t))
293 |
294 | ;; evil integration
295 | (when (bound-and-true-p evil-fold-list)
296 | (add-to-list 'evil-fold-list
297 | '((treesit-fold-mode)
298 | :toggle treesit-fold-toggle
299 | :open treesit-fold-open
300 | :close treesit-fold-close
301 | :open-rec treesit-fold-open-recursively
302 | :open-all treesit-fold-open-all
303 | :close-all treesit-fold-close-all))))
304 |
305 | (defun treesit-fold--disable ()
306 | "Stop folding minor mode."
307 | (remove-from-invisibility-spec '(treesit-fold . t))
308 | (treesit-fold-open-all))
309 |
310 | (defun treesit-fold-ready-p ()
311 | "Return non-nil if the current buffer has a tree-sitter parser."
312 | (treesit-parser-list))
313 |
314 | (defun treesit-fold--trigger ()
315 | "Enable `treesit-fold-mode' when the current mode is treesit-fold compatible."
316 | (when (and (treesit-fold-ready-p)
317 | (treesit-fold-usable-mode-p))
318 | (treesit-fold-mode 1)))
319 |
320 | ;;;###autoload
321 | (define-minor-mode treesit-fold-mode
322 | "Folding code using tree sitter."
323 | :group 'treesit-fold
324 | :init-value nil
325 | :lighter " Treesit-Fold"
326 | :keymap treesit-fold-mode-map
327 | (cond
328 | ((not (and (treesit-available-p)
329 | (treesit-parser-list)
330 | (treesit-fold-usable-mode-p)))
331 | (when treesit-fold-mode
332 | (treesit-fold-mode -1)))
333 | (treesit-fold-mode
334 | (treesit-fold--enable) t)
335 | (t
336 | (treesit-fold--disable))))
337 |
338 | ;;;###autoload
339 | (define-globalized-minor-mode global-treesit-fold-mode
340 | treesit-fold-mode treesit-fold--trigger
341 | :group 'treesit-fold)
342 |
343 | (defun treesit-fold-usable-mode-p (&optional mode)
344 | "Return non-nil if `treesit-fold' has defined folds for MODE."
345 | (let ((mode (or mode major-mode)))
346 | (alist-get mode treesit-fold-range-alist)))
347 |
348 | ;;;###autoload
349 | (define-minor-mode treesit-fold-line-comment-mode
350 | "Enable line comment folding."
351 | :group 'treesit-fold
352 | :init-value nil
353 | (treesit-fold--indicators-refresh))
354 |
355 | ;;
356 | ;; (@* "Core" )
357 | ;;
358 |
359 | (defun treesit-fold--range-on-same-line (range)
360 | "Return non-nil if RANGE is on the same line."
361 | (let ((beg (car range))
362 | (end (cdr range))
363 | (lbp) (lep))
364 | (save-excursion
365 | (goto-char beg)
366 | (setq lbp (line-beginning-position)
367 | lep (line-end-position)))
368 | (and (<= lbp beg) (<= beg lep)
369 | (<= lbp end) (<= end lep))))
370 |
371 | (defun treesit-fold--get-fold-range (node)
372 | "Return the beginning (as buffer position) of fold for NODE.
373 | Return nil if there is no fold to be made."
374 | (when-let* ((fold-alist (alist-get major-mode treesit-fold-range-alist))
375 | (fold-func (alist-get (intern (treesit-node-type node)) fold-alist)))
376 | (cond ((functionp fold-func) (funcall fold-func node (cons 0 0)))
377 | ((listp fold-func) (funcall (nth 0 fold-func) node (cons (nth 1 fold-func) (nth 2 fold-func))))
378 | (t (user-error "Bad folding function for node")))))
379 |
380 | (defun treesit-fold--node-range-on-same-line (node)
381 | "Return non-nil when NODE range is on the same line."
382 | (let ((range (treesit-fold--get-fold-range node)))
383 | (or (not range) ; Range not defined, continue.
384 | (treesit-fold--range-on-same-line range)))) ; On same line, continue.
385 |
386 | (defun treesit-fold--non-foldable-node-p (node mode-ranges)
387 | "Return non-nil if NODE is a non-foldable in MODE-RANGES."
388 | (or (not (alist-get (intern (treesit-node-type node)) mode-ranges)) ; Not registered, continue.
389 | (treesit-fold--node-range-on-same-line node))) ; On same line, continue.
390 |
391 | (defun treesit-fold--foldable-node-at-pos (&optional pos)
392 | "Return the smallest foldable node at POS. If POS is nil, use `point'.
393 |
394 | Return nil if no valid node is found.
395 |
396 | This function is borrowed from `tree-sitter-node-at-point'."
397 | (let* ((pos (or pos (point)))
398 | (mode-ranges (alist-get major-mode treesit-fold-range-alist))
399 | (root (treesit-buffer-root-node))
400 | (node (treesit-node-descendant-for-range root pos pos))
401 | ;; Used for looping
402 | (current node))
403 | (while (and current
404 | (treesit-fold--non-foldable-node-p current mode-ranges))
405 | (setq current (treesit-node-parent current)))
406 | current))
407 |
408 | ;;
409 | ;; (@* "Overlays" )
410 | ;;
411 |
412 | (defun treesit-fold--format-overlay-text (beg end)
413 | "Return the text to display in the overlay for the fold from BEG to END."
414 | (let ((summary (and treesit-fold-summary-show
415 | (treesit-fold-summary--get (buffer-substring beg end)))))
416 | (cond
417 | ;; Handle line count display.
418 | ((when-let*
419 | ((line-count (and treesit-fold-line-count-show
420 | (count-lines beg end)))
421 | (line-count-str (format treesit-fold-line-count-format line-count)))
422 | (concat (or summary "") line-count-str)))
423 | ;; `summary' handles truncation itself; just return it if not nil.
424 | (summary )
425 | ;; Fallback to ellipsis.
426 | (t (truncate-string-ellipsis)))))
427 |
428 | (defun treesit-fold--create-overlay (range)
429 | "Create invisible overlay in RANGE."
430 | (when range
431 | (let* ((beg (car range))
432 | (end (cdr range))
433 | (ov (make-overlay beg end))
434 | (map (make-sparse-keymap)))
435 | (define-key map (kbd "") #'treesit-fold-open)
436 | (overlay-put ov 'creator 'treesit-fold)
437 | (overlay-put ov 'priority treesit-fold-priority)
438 | (overlay-put ov 'invisible 'treesit-fold)
439 | (overlay-put ov 'display
440 | (propertize (treesit-fold--format-overlay-text beg end)
441 | 'mouse-face 'treesit-fold-replacement-mouse-face
442 | 'help-echo "mouse-1: unfold this node"
443 | 'keymap map))
444 | (overlay-put ov 'face 'treesit-fold-replacement-face)
445 | (overlay-put ov 'modification-hooks '(treesit-fold--on-change))
446 | (overlay-put ov 'insert-in-front-hooks '(treesit-fold--on-change))
447 | (overlay-put ov 'isearch-open-invisible #'treesit-fold--on-change)
448 | (overlay-put ov 'isearch-open-invisible-temporary #'treesit-fold--open-invisible-temporary)
449 | ov)))
450 |
451 | (defun treesit-fold--open-invisible-temporary (ov hide-p)
452 | "Temporary show/hide OV depends on HIDE-P flag."
453 | (if hide-p (treesit-fold--hide-ov ov)
454 | (treesit-fold--show-ov ov)))
455 |
456 | (defun treesit-fold--on-change (ov &rest _)
457 | "Open overlay OV during content is changed."
458 | (delete-overlay ov))
459 |
460 | (defun treesit-fold--show-ov (ov &rest _)
461 | "Show the OV."
462 | (overlay-put ov 'invisible nil)
463 | (overlay-put ov 'display nil)
464 | (overlay-put ov 'face nil)
465 | (treesit-fold--indicators-refresh))
466 |
467 | (defun treesit-fold--hide-ov (ov &rest _)
468 | "Hide the OV."
469 | (let ((beg (overlay-start ov))
470 | (end (overlay-end ov)))
471 | (overlay-put ov 'invisible 'treesit-fold)
472 | (overlay-put ov 'display
473 | (propertize (treesit-fold--format-overlay-text beg end)
474 | 'mouse-face 'treesit-fold-replacement-mouse-face
475 | 'help-echo "mouse-1: unfold this node"
476 | 'keymap (overlay-get ov 'keymap)))
477 | (overlay-put ov 'face 'treesit-fold-replacement-face))
478 | (treesit-fold--indicators-refresh))
479 |
480 | (defun treesit-fold-overlay-at (node)
481 | "Return the treesit-fold overlay at NODE if NODE is foldable and folded.
482 | Return nil otherwise."
483 | (when-let* ((range (treesit-fold--get-fold-range node)))
484 | (thread-last (overlays-in (car range) (cdr range))
485 | (seq-filter (lambda (ov)
486 | (and (eq (overlay-get ov 'invisible) 'treesit-fold)
487 | (= (overlay-start ov) (car range))
488 | (= (overlay-end ov) (cdr range)))))
489 | car)))
490 |
491 | ;;
492 | ;; (@* "Commands" )
493 | ;;
494 |
495 | (defmacro treesit-fold--ensure-ts (&rest body)
496 | "Run BODY only if `tree-sitter-mode` is enabled."
497 | (declare (indent 0))
498 | `(if (treesit-fold-ready-p)
499 | (progn ,@body)
500 | (user-error "Ignored, no tree-sitter parser in current buffer")))
501 |
502 | ;;;###autoload
503 | (defun treesit-fold-close (&optional node)
504 | "Fold the syntax node at `point` if it is foldable.
505 |
506 | Foldable nodes are defined in `treesit-fold-range-alist' for the
507 | current `major-mode'.
508 |
509 | If no NODE is found in point, do nothing."
510 | (interactive)
511 | (treesit-fold--ensure-ts
512 | (when-let* ((node (or node (treesit-fold--foldable-node-at-pos))))
513 | ;; make sure I do not create multiple overlays for the same fold
514 | (when-let* ((ov (treesit-fold-overlay-at node)))
515 | (delete-overlay ov))
516 | (when-let* ((range (treesit-fold--get-fold-range node))
517 | (ov (treesit-fold--create-overlay range)))
518 | (run-hooks 'treesit-fold-on-fold-hook)
519 | ov))))
520 |
521 | ;;;###autoload
522 | (defun treesit-fold-open ()
523 | "Open the fold of the syntax node in which `point' resides.
524 | If the current node is not folded or not foldable, do nothing."
525 | (interactive)
526 | (treesit-fold--ensure-ts
527 | (when-let* ((node (treesit-fold--foldable-node-at-pos))
528 | (ov (treesit-fold-overlay-at node)))
529 | (delete-overlay ov)
530 | (run-hooks 'treesit-fold-on-fold-hook)
531 | t)))
532 |
533 | ;;;###autoload
534 | (defun treesit-fold-open-recursively ()
535 | "Open recursively folded syntax NODE that are contained in the node at point."
536 | (interactive)
537 | (treesit-fold--ensure-ts
538 | (when-let* ((node (treesit-fold--foldable-node-at-pos))
539 | (beg (treesit-node-start node))
540 | (end (treesit-node-end node))
541 | (nodes (treesit-fold--overlays-in 'invisible 'treesit-fold beg end)))
542 | (mapc #'delete-overlay nodes)
543 | (run-hooks 'treesit-fold-on-fold-hook)
544 | t)))
545 |
546 | ;;;###autoload
547 | (defun treesit-fold-close-all ()
548 | "Fold all foldable syntax nodes in the buffer."
549 | (interactive)
550 | (treesit-fold--ensure-ts
551 | (let (nodes)
552 | (let* ((treesit-fold-indicators-mode)
553 | (treesit-fold-on-fold-hook)
554 | (node (treesit-buffer-root-node))
555 | (patterns (seq-mapcat (lambda (fold-range) `((,(car fold-range)) @name))
556 | (alist-get major-mode treesit-fold-range-alist)))
557 | (query (treesit-query-compile (treesit-node-language node) patterns)))
558 | (setq nodes (treesit-query-capture node query)
559 | nodes (cl-remove-if (lambda (node)
560 | ;; Removed if on same line
561 | (treesit-fold--node-range-on-same-line (cdr node)))
562 | nodes))
563 | (thread-last nodes
564 | (mapcar #'cdr)
565 | (mapc #'treesit-fold-close)))
566 | (when nodes
567 | (run-hooks 'treesit-fold-on-fold-hook)
568 | t))))
569 |
570 | ;;;###autoload
571 | (defun treesit-fold-open-all ()
572 | "Unfold all syntax nodes in the buffer."
573 | (interactive)
574 | (treesit-fold--ensure-ts
575 | (when-let* ((nodes (treesit-fold--overlays-in 'invisible 'treesit-fold)))
576 | (mapc #'delete-overlay nodes)
577 | (run-hooks 'treesit-fold-on-fold-hook)
578 | t)))
579 |
580 | ;;;###autoload
581 | (defun treesit-fold-toggle ()
582 | "Toggle the syntax node at `point'.
583 | If the current syntax node is not foldable, do nothing."
584 | (interactive)
585 | (treesit-fold--ensure-ts
586 | (if-let* ((node (treesit-fold--foldable-node-at-pos (point)))
587 | (ov (treesit-fold-overlay-at node)))
588 | (progn
589 | (delete-overlay ov)
590 | (run-hooks 'treesit-fold-on-fold-hook)
591 | t)
592 | (treesit-fold-close))))
593 |
594 | (defun treesit-fold--after-command (&rest _)
595 | "Function call after interactive commands."
596 | (treesit-fold--indicators-refresh))
597 |
598 | (let ((commands '(treesit-fold-close
599 | treesit-fold-open
600 | treesit-fold-open-recursively
601 | treesit-fold-close-all
602 | treesit-fold-open-all
603 | treesit-fold-toggle)))
604 | (dolist (command commands)
605 | (advice-add command :after #'treesit-fold--after-command)))
606 |
607 | ;;
608 | ;; (@* "Rule Helpers" )
609 | ;;
610 |
611 | (defun treesit-fold--next-prev-node (node next)
612 | "Return previous/next sibling node starting from NODE.
613 |
614 | If NEXT is non-nil, return next sibling. Otherwirse, return previouse sibling."
615 | (if next (treesit-node-next-sibling node) (treesit-node-prev-sibling node)))
616 |
617 | (defun treesit-fold--next-prev-node-skip-newline (node next)
618 | "Like function `treesit-fold--next-prev-node'.
619 |
620 | For arguments NODE and NEXT, please see the function
621 | `treesit-fold--next-prev-node' for more information."
622 | (let ((iter-node (treesit-fold--next-prev-node node next)))
623 | (while (and iter-node
624 | (equal "\n" (ignore-errors (treesit-node-text iter-node))))
625 | (setq iter-node (treesit-fold--next-prev-node iter-node next)))
626 | iter-node))
627 |
628 | (defun treesit-fold--continuous-node-prefix (node prefix next)
629 | "Iterate through node starting from NODE and compare node-text to PREFIX;
630 | then return the last iterated node.
631 |
632 | Argument NEXT is a boolean type. If non-nil iterate forward; otherwise iterate
633 | in backward direction."
634 | (let* ((iter-node node) (last-node node)
635 | (last-line (car (treesit-fold--node-start-point node))) line text break
636 | (line-range 1) (last-line-range 1) max-line-range
637 | (indentation (treesit-fold--indentation (treesit-node-start iter-node)))
638 | next-indentation)
639 | (while (and iter-node (not break))
640 | (setq text (string-trim (treesit-node-text iter-node))
641 | line (car (treesit-fold--node-start-point iter-node))
642 | line-range (1+ (treesit-fold--count-matches "\n" text))
643 | max-line-range (max line-range last-line-range)
644 | next-indentation (treesit-fold--indentation (treesit-node-start iter-node)))
645 | (if (and (treesit-fold--in-range-p line (- last-line max-line-range) (+ last-line max-line-range))
646 | (string-prefix-p prefix text)
647 | (= indentation next-indentation))
648 | (setq last-node iter-node last-line line
649 | last-line-range (1+ (treesit-fold--count-matches "\n" text)))
650 | (setq break t))
651 | (setq iter-node (treesit-fold--next-prev-node-skip-newline iter-node next)))
652 | last-node))
653 |
654 | (defun treesit-fold-range-seq (node offset)
655 | "Return the fold range in sequence starting from NODE.
656 |
657 | Argument OFFSET can be used to tweak the final beginning and end position."
658 | (let ((beg (1+ (treesit-node-start node)))
659 | (end (1- (treesit-node-end node))))
660 | (treesit-fold--cons-add (cons beg end) offset)))
661 |
662 | (defun treesit-fold-range-markers (node offset start-seq &optional end-seq)
663 | "Return the fold range for NODE with an OFFSET where the range starts at
664 | the end of the first occurence of START-SEQ and ends at the end of the node
665 | or the start of the last occurence of the optional parameter LAST-SEQ.
666 |
667 | START-SEQ and LAST-SEQ can be named tree-sitter nodes or anonomous nodes.
668 |
669 | If no occurence is found for START-SEQ or END-SEQ or the
670 | occurences overlap, then the range returned is nil."
671 | (when start-seq
672 | (when-let* ((beg-node (car (treesit-fold-find-children node start-seq)))
673 | (end-node (if end-seq
674 | (car (last (treesit-fold-find-children node end-seq)))
675 | node))
676 | (beg (treesit-node-end beg-node))
677 | (end (if end-seq
678 | (treesit-node-start end-node)
679 | (1- (treesit-node-end node)))))
680 | (unless (> beg end) (treesit-fold--cons-add (cons beg end) offset)))))
681 |
682 | (defun treesit-fold-range-line-comment (node offset prefix)
683 | "Define fold range for line comment.
684 |
685 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
686 | more information.
687 |
688 | Argument PREFIX is the comment prefix in string."
689 | (save-excursion
690 | (when-let* ((treesit-fold-line-comment-mode) ; XXX: Check enabled!?
691 | (first-node (ignore-errors
692 | (treesit-fold--continuous-node-prefix node prefix nil)))
693 | (last-node (ignore-errors
694 | (treesit-fold--continuous-node-prefix node prefix t)))
695 | (prefix-len (length prefix))
696 | (beg (+ (treesit-node-start first-node) prefix-len))
697 | (end (treesit-node-end last-node)))
698 | (treesit-fold--cons-add (cons beg end) offset))))
699 |
700 | (defun treesit-fold-range-block-comment (node offset)
701 | "Define fold range for block comment.
702 |
703 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
704 | more information."
705 | (treesit-fold-range-seq node (treesit-fold--cons-add '(1 . -1) offset)))
706 |
707 | (defun treesit-fold-range-c-like-comment (node offset)
708 | "Define fold range for C-like comemnt.
709 |
710 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
711 | more information."
712 | (let ((text (treesit-node-text node)))
713 | (if (and (string-match-p "\n" text) (string-prefix-p "/*" text))
714 | (treesit-fold-range-block-comment node offset)
715 | (if (string-prefix-p "///" text)
716 | (treesit-fold-range-line-comment node offset "///")
717 | (treesit-fold-range-line-comment node offset "//")))))
718 |
719 | ;;
720 | ;; (@* "Languages" )
721 | ;;
722 |
723 | (defun treesit-fold-range-asm--find-last-instruction (node)
724 | "Find the last instruction node by starting NODE."
725 | (let* ((iter-node (treesit-fold--next-prev-node-skip-newline node t))
726 | (last iter-node))
727 | (while (and iter-node
728 | (not (member (treesit-node-type iter-node)
729 | (treesit-fold-listify "label"))))
730 | (setq last iter-node
731 | iter-node (treesit-fold--next-prev-node-skip-newline iter-node t)))
732 | last)) ; return last insturction node
733 |
734 | (defun treesit-fold-range-asm-label (node offset)
735 | "Define fold range for `label' in Assembly.
736 |
737 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
738 | more information."
739 | (when-let* ((beg (treesit-node-end node))
740 | (end (treesit-fold-range-asm--find-last-instruction node))
741 | (end (treesit-node-end end)))
742 | (treesit-fold--cons-add (cons beg end) offset)))
743 |
744 | (defun treesit-fold-range-beancount-transaction (node offset)
745 | "Define fold range for `transaction' in Beancount.
746 |
747 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
748 | more information."
749 | (when-let* ((beg (treesit-node-start node))
750 | (beg (treesit-fold--eol beg))
751 | (end (1- (treesit-node-end node))))
752 | (treesit-fold--cons-add (cons beg end) offset)))
753 |
754 | (defun treesit-fold-range-c-preproc-if (node offset)
755 | "Define fold range for `if' preprocessor.
756 |
757 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
758 | more information."
759 | (let* ((named-node (treesit-node-child-by-field-name node "condition"))
760 | (else (or (treesit-node-child-by-field-name node "alternative")
761 | (car (treesit-fold-find-children node "#endif"))))
762 | (beg (treesit-node-end named-node))
763 | (end (1- (treesit-node-start else))))
764 | (treesit-fold--cons-add (cons beg end) offset)))
765 |
766 | (defun treesit-fold-range-c-preproc-ifdef (node offset)
767 | "Define fold range for `ifdef' and `ifndef' preprocessor.
768 |
769 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
770 | more information."
771 | (when-let* ((named-node (treesit-node-child-by-field-name node "name"))
772 | (else (or (treesit-node-child-by-field-name node "alternative")
773 | (car (treesit-fold-find-children node "#endif"))))
774 | (beg (treesit-node-end named-node))
775 | (end (1- (treesit-node-start else))))
776 | (treesit-fold--cons-add (cons beg end) offset)))
777 |
778 | (defun treesit-fold-range-c-preproc-elif (node offset)
779 | "Define fold range for `elif' preprocessor.
780 |
781 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
782 | more information."
783 | (when-let* ((named-node (treesit-node-child-by-field-name node "condition"))
784 | (parent (or (treesit-fold-find-parent node "preproc_if")
785 | (treesit-fold-find-parent node "preproc_ifdef")))
786 | (next (or (treesit-node-child-by-field-name node "alternative")
787 | (car (treesit-fold-find-children parent "#endif"))))
788 | (beg (treesit-node-end named-node))
789 | (end (1- (treesit-node-start next))))
790 | (treesit-fold--cons-add (cons beg end) offset)))
791 |
792 | (defun treesit-fold-range-c-preproc-else (node offset)
793 | "Define fold range for `else' preprocessor.
794 |
795 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
796 | more information."
797 | (when-let* ((else-str (car (split-string (treesit-node-text node) "\n")))
798 | (parent (or (treesit-fold-find-parent node "preproc_if")
799 | (treesit-fold-find-parent node "preproc_ifdef")))
800 | (next (car (treesit-fold-find-children parent "#endif")))
801 | (beg (+ (treesit-node-start node) (length else-str)))
802 | (end (1- (treesit-node-start next))))
803 | (treesit-fold--cons-add (cons beg end) offset)))
804 |
805 | (defun treesit-fold-range-clojure-function (node offset)
806 | "Return the fold range for `list_lit' NODE in Clojure.
807 |
808 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
809 | more information."
810 | (when-let* ((name-node (nth 1 (treesit-fold-find-children node "sym_lit")))
811 | (next-node (treesit-node-next-sibling name-node))
812 | (beg (treesit-node-start next-node))
813 | (end (1- (treesit-node-end node))))
814 | (unless treesit-fold-on-next-line ; display nicely
815 | (setq beg (treesit-fold--last-eol beg)))
816 | (treesit-fold--cons-add (cons beg end) offset)))
817 |
818 | (defun treesit-fold-range-cmake-body (node offset)
819 | "Return the fold range for `body' NODE in CMake.
820 |
821 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
822 | more information."
823 | (when-let* ((beg (treesit-node-start node))
824 | (end (treesit-node-end node)))
825 | (when treesit-fold-on-next-line ; display nicely
826 | (setq end (treesit-fold--last-eol end)))
827 | (treesit-fold--cons-add (cons beg end) offset)))
828 |
829 | (defun treesit-fold-range-editorconfig-end-section (node)
830 | "Return the section NODE's end point."
831 | (let ((pt (treesit-node-end node))
832 | (children (reverse (treesit-node-children node))))
833 | (or (cl-some (lambda (child)
834 | (when (equal 'pair (treesit-node-type child))
835 | (treesit-node-end child)))
836 | children)
837 | pt)))
838 |
839 | (defun treesit-fold-range-editorconfig-section (node offset)
840 | "Return the fold range for `section' NODE in EditorConfig.
841 |
842 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
843 | more information."
844 | (when-let* ((end-bracket (car (treesit-fold-find-children node "]")))
845 | (beg (treesit-node-end end-bracket))
846 | (end (1- (treesit-fold-range-editorconfig-end-section node))))
847 | (treesit-fold--cons-add (cons beg end) offset)))
848 |
849 | (defun treesit-fold-range-elisp-function (node offset)
850 | "Return the fold range for `macro_definition' and `function_definition' NODE
851 | in Elisp.
852 |
853 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
854 | more information."
855 | (when-let* ((param-node (treesit-node-child node 4))
856 | (beg (treesit-node-start param-node))
857 | (end (1- (treesit-node-end node))))
858 | (unless treesit-fold-on-next-line ; display nicely
859 | (setq beg (treesit-fold--last-eol beg)))
860 | (treesit-fold--cons-add (cons beg end) offset)))
861 |
862 | (defun treesit-fold-range-elixir (node offset)
863 | "Return the fold range for `function' `module' NODE in Elixir.
864 |
865 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
866 | more information."
867 | (when-let* ((end-child (treesit-fold-last-child node))
868 | (do-child (treesit-node-child node 1))
869 | (beg (treesit-node-start do-child))
870 | (beg (treesit-fold--last-eol beg))
871 | (end (treesit-node-start end-child)))
872 | (when treesit-fold-on-next-line ; display nicely
873 | (setq end (treesit-fold--last-eol end)))
874 | (treesit-fold--cons-add (cons beg end) offset)))
875 |
876 | (defun treesit-fold-range-erlang-signature (node offset start)
877 | "Return the fold range for generic signature NODE in Erlang.
878 |
879 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
880 | more information.
881 |
882 | Argument START is a string to target for the first node we use to find the
883 | start of the position."
884 | (when-let* ((start-node (car (treesit-fold-find-children node start)))
885 | (beg (treesit-node-end start-node))
886 | (end (treesit-node-end node)))
887 | (treesit-fold--cons-add (cons beg end) offset)))
888 |
889 | (defun treesit-fold-range-erlang-clause-body (node offset)
890 | "Return the fold range for `clause_body' NODE in Erlang.
891 |
892 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
893 | more information."
894 | (treesit-fold-range-erlang-signature node offset "->"))
895 |
896 | (defun treesit-fold-range-erlang-type-guards (node offset)
897 | "Return the fold range for `type_guards' NODE in Erlang.
898 |
899 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
900 | more information."
901 | (treesit-fold-range-erlang-signature node offset "when"))
902 |
903 | (defun treesit-fold-range-fish-function (node offset)
904 | "Define fold range for `function' in Fish.
905 |
906 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
907 | more information."
908 | (when-let* ((func-name (treesit-node-child node 1))
909 | (beg (treesit-node-end func-name))
910 | (end (treesit-node-end node))
911 | (end (- end 3)))
912 | (when treesit-fold-on-next-line ; display nicely
913 | (setq end (treesit-fold--last-eol end)))
914 | (treesit-fold--cons-add (cons beg end) offset)))
915 |
916 | (defun treesit-fold-range-fish-if (node offset)
917 | "Define fold range for `if_statement' in Fish.
918 |
919 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
920 | more information."
921 | (when-let* ((beg (treesit-node-start node))
922 | (beg (treesit-fold--eol beg))
923 | (end (treesit-node-end node))
924 | (end (- end 3)))
925 | (when treesit-fold-on-next-line ; display nicely
926 | (setq end (treesit-fold--last-eol end)))
927 | (treesit-fold--cons-add (cons beg end) offset)))
928 |
929 | (defun treesit-fold-range-fish-case (node offset)
930 | "Define fold range for `case_clause' in Fish.
931 |
932 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
933 | more information."
934 | (when-let* ((beg (treesit-node-start node))
935 | (beg (treesit-fold--eol beg))
936 | (end (treesit-node-end node))
937 | (end (1- end)))
938 | (treesit-fold--cons-add (cons beg end) offset)))
939 |
940 | (defun treesit-fold-range-gleam (node offset)
941 | "Return the fold range for `function' `type_definition' NODE in Gleam.
942 |
943 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
944 | more information."
945 | (when-let* ((open-bracket (car (treesit-fold-find-children node "{")))
946 | (beg (treesit-node-start open-bracket))
947 | (beg (1+ beg))
948 | (end (treesit-node-end node))
949 | (end (1- end)))
950 | (treesit-fold--cons-add (cons beg end) offset)))
951 |
952 | (defun treesit-fold-range-groovy-block (node offset)
953 | "Define fold range for `block' in Groovy.
954 |
955 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
956 | more information."
957 | (when-let* ((open-bracket (car (treesit-fold-find-children node "{")))
958 | (beg (treesit-node-start open-bracket))
959 | (beg (1+ beg))
960 | (end (treesit-node-end node))
961 | (end (1- end)))
962 | (treesit-fold--cons-add (cons beg end) offset)))
963 |
964 | (defun treesit-fold-range-haskell-function (node offset)
965 | "Define fold range for `function' in Haskell.
966 |
967 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
968 | more information."
969 | (when-let* ((beg (treesit-node-start node))
970 | (beg (treesit-fold--eol beg))
971 | (end-node (treesit-fold-last-child node))
972 | (end (treesit-node-end end-node)))
973 | (treesit-fold--cons-add (cons beg end) offset)))
974 |
975 | (defun treesit-fold-range-html (node offset)
976 | "Define fold range for tag in HTML.
977 |
978 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
979 | more information."
980 | (let* ((beg (treesit-node-end (treesit-node-child node 0)))
981 | (end-node (treesit-fold-last-child node))
982 | (end (treesit-node-start end-node)))
983 | (treesit-fold--cons-add (cons beg end) offset)))
984 |
985 | (defun treesit-fold-range-julia-function (node offset)
986 | "Return the fold range for a NODE in Julia.
987 |
988 | It excludes the NODE's first child and the `end' keyword. For
989 | argument OFFSET, see function `treesit-fold-range-seq' for more
990 | information."
991 | (when-let* ((identifier (treesit-node-child node 0 t))
992 | (params (treesit-node-child node 1 t))
993 | (beg (treesit-node-end params))
994 | (end (treesit-node-end node))
995 | (end (- end 3)))
996 | (when treesit-fold-on-next-line ; display nicely
997 | (setq end (treesit-fold--last-eol end)))
998 | (treesit-fold--cons-add (cons beg end) offset)))
999 |
1000 | (defun treesit-fold-range-julia-if (node offset)
1001 | "Define fold range for if statement in Julia.
1002 |
1003 | It excludes the NODE's first child and the `end' keyword. For
1004 | argument OFFSET, see function `treesit-fold-range-seq' for more
1005 | information."
1006 | (when-let* ((params (treesit-node-child node 0 t))
1007 | (beg (treesit-node-end params))
1008 | (end (treesit-node-end node))
1009 | (end (- end 3)))
1010 | (when treesit-fold-on-next-line ; display nicely
1011 | (setq end (treesit-fold--last-eol end)))
1012 | (treesit-fold--cons-add (cons beg end) offset)))
1013 |
1014 | (defun treesit-fold-range-julia-let (node offset)
1015 | "Define fold range for let statement in Julia.
1016 |
1017 | It excludes the NODE's first child and the `end' keyword. For
1018 | argument OFFSET, see function `treesit-fold-range-seq' for more
1019 | information."
1020 | (when-let* ((vars (treesit-fold-find-children node "variable_declaration"))
1021 | (last-var (last vars))
1022 | (last-var (car last-var))
1023 | (beg (treesit-node-end last-var))
1024 | (end (treesit-node-end node))
1025 | (end (- end 3)))
1026 | (when treesit-fold-on-next-line ; display nicely
1027 | (setq end (treesit-fold--last-eol end)))
1028 | (treesit-fold--cons-add (cons beg end) offset)))
1029 |
1030 | (defun treesit-fold-range-kotlin-when (node offset)
1031 | "Return the fold range for `when' NODE in Kotlin.
1032 |
1033 | It excludes the NODE's first child and the `end' keyword. For
1034 | argument OFFSET, see function `treesit-fold-range-seq' for more
1035 | information."
1036 | (when-let* ((open-bracket (car (treesit-fold-find-children node "{")))
1037 | (beg (treesit-node-end open-bracket))
1038 | (end (1- (treesit-node-end node))))
1039 | (treesit-fold--cons-add (cons beg end) offset)))
1040 |
1041 | (defun treesit-fold-range-latex-environment (node offset)
1042 | "Define fold range for latex environments.
1043 |
1044 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1045 | more information."
1046 | (when-let* ((beg-node (treesit-node-child-by-field-name node "begin"))
1047 | (end-node (treesit-node-child-by-field-name node "end"))
1048 | (beg (treesit-node-end beg-node))
1049 | (end (treesit-node-start end-node)))
1050 | (treesit-fold--cons-add (cons beg end) offset)))
1051 |
1052 | (defun treesit-fold-range-latex-section (node offset)
1053 | "Define fold range for latex section.
1054 |
1055 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1056 | more information."
1057 | (when-let* ((lab-node (car (treesit-fold-find-children node "curly_group")))
1058 | (beg (treesit-node-end lab-node))
1059 | (end (treesit-node-end node)))
1060 | (treesit-fold--cons-add (cons beg end) offset)))
1061 |
1062 | (defun treesit-fold-range-lisp-function (node offset)
1063 | "Define fold range for function in Lisp .
1064 |
1065 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1066 | more information."
1067 | (when-let* ((header (car (treesit-fold-find-children node "defun_header")))
1068 | (body (treesit-node-next-sibling header))
1069 | (beg (treesit-node-start body))
1070 | (end (1- (treesit-node-end node))))
1071 | (treesit-fold--cons-add (cons beg end) offset)))
1072 |
1073 | (defun treesit-fold-range-llvm--find-last-instruction (node)
1074 | "Find the last instruction node by starting NODE."
1075 | (let* ((iter-node (treesit-fold--next-prev-node-skip-newline node t))
1076 | (last iter-node))
1077 | (while (and iter-node
1078 | (not (member (treesit-node-type iter-node)
1079 | (treesit-fold-listify '("label" "}")))))
1080 | (setq last iter-node
1081 | iter-node (treesit-fold--next-prev-node-skip-newline iter-node t)))
1082 | last)) ; return last insturction node
1083 |
1084 | (defun treesit-fold-range-llvm-label (node offset)
1085 | "Define fold range for `label' in LLVM.
1086 |
1087 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1088 | more information."
1089 | (when-let* ((beg (treesit-node-end node))
1090 | (end (treesit-fold-range-llvm--find-last-instruction node))
1091 | (end (treesit-node-end end)))
1092 | (treesit-fold--cons-add (cons beg end) offset)))
1093 |
1094 | (defun treesit-fold-range-llvm-mir-label (node offset)
1095 | "Define fold range for `label' in LLVM MIR.
1096 |
1097 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1098 | more information."
1099 | (when-let* ((label (car (treesit-fold-find-children node "label")))
1100 | (colon (treesit-node-next-sibling label))
1101 | (beg (treesit-node-end colon))
1102 | (beg (treesit-fold--eol beg))
1103 | (end (treesit-fold-range-llvm--find-last-instruction label))
1104 | (end (treesit-node-end end)))
1105 | (treesit-fold--cons-add (cons beg end) offset)))
1106 |
1107 | (defun treesit-fold-range-lua-comment (node offset)
1108 | "Define fold range for Lua comemnt.
1109 |
1110 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1111 | more information."
1112 | (let ((text (treesit-node-text node)))
1113 | (if (and (string-match-p "\n" text) (string-prefix-p "--[[" text))
1114 | (treesit-fold-range-block-comment node
1115 | ;; XXX: Add 2 to for ]] at the end
1116 | (treesit-fold--cons-add (cons 2 0) offset))
1117 | (treesit-fold-range-line-comment node offset "--"))))
1118 |
1119 | (defun treesit-fold-range-lua-function (node offset)
1120 | "Define fold range for Lua `function' declaration.
1121 |
1122 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1123 | more information."
1124 | (let* ((params (treesit-node-child-by-field-name node "parameters"))
1125 | (beg (treesit-node-end params))
1126 | (end (- (treesit-node-end node) 3))) ; fit identifier `end'
1127 | (when treesit-fold-on-next-line ; display nicely
1128 | (setq end (treesit-fold--last-eol end)))
1129 | (treesit-fold--cons-add (cons beg end) offset)))
1130 |
1131 | (defun treesit-fold-range-lua-if (node offset)
1132 | "Define fold range for Lua `if' statement.
1133 |
1134 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1135 | more information."
1136 | (let* ((then (car (treesit-fold-find-children node "then")))
1137 | (beg (treesit-node-end then))
1138 | (next (or (treesit-fold-find-children node "elseif_statement")
1139 | (treesit-fold-find-children node "else_statement")))
1140 | (end (if next
1141 | (treesit-node-start (car next))
1142 | (- (treesit-node-end node) 3))))
1143 | (when treesit-fold-on-next-line ; display nicely
1144 | (setq end (treesit-fold--last-eol end)))
1145 | (treesit-fold--cons-add (cons beg end) offset)))
1146 |
1147 | (defun treesit-fold-range-lua-elseif (node offset)
1148 | "Define fold range for Lua `elseif' statement.
1149 |
1150 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1151 | more information."
1152 | (let* ((then (car (treesit-fold-find-children node "then")))
1153 | (beg (treesit-node-end then))
1154 | (next (treesit-node-next-sibling node))
1155 | (end (if next
1156 | (treesit-node-start next)
1157 | (treesit-node-end node))))
1158 | (when treesit-fold-on-next-line ; display nicely
1159 | (setq end (treesit-fold--last-eol end)))
1160 | (treesit-fold--cons-add (cons beg end) offset)))
1161 |
1162 | (defun treesit-fold-range-lua-else (node offset)
1163 | "Define fold range for Lua `else' statement.
1164 |
1165 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1166 | more information."
1167 | (let* ((beg (+ (treesit-node-start node) 4)) ; fit `else', 4 letters
1168 | (next (treesit-node-next-sibling node)) ; the `end' node
1169 | (end (treesit-node-start next)))
1170 | (when treesit-fold-on-next-line ; display nicely
1171 | (setq end (treesit-fold--last-eol end)))
1172 | (treesit-fold--cons-add (cons beg end) offset)))
1173 |
1174 | (defun treesit-fold-range-lua-do-loop (node offset)
1175 | "Define fold range for Lua `while' and `for' statement.
1176 |
1177 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1178 | more information."
1179 | (let* ((do (car (treesit-fold-find-children node "do")))
1180 | (beg (treesit-node-end do))
1181 | (end (- (treesit-node-end node) 3)))
1182 | (when treesit-fold-on-next-line ; display nicely
1183 | (setq end (treesit-fold--last-eol end)))
1184 | (treesit-fold--cons-add (cons beg end) offset)))
1185 |
1186 | (defun treesit-fold-range-lua-repeat (node offset)
1187 | "Define fold range for Lua `repeat' statement.
1188 |
1189 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1190 | more information."
1191 | (let* ((beg (+ (treesit-node-start node) 6)) ; fit `repeat', 6 letters
1192 | (until (car (treesit-fold-find-children node "until")))
1193 | (end (treesit-node-start until)))
1194 | (when treesit-fold-on-next-line ; display nicely
1195 | (setq end (treesit-fold--last-eol end)))
1196 | (treesit-fold--cons-add (cons beg end) offset)))
1197 |
1198 | (defun treesit-fold-range-make-recipe (node offset)
1199 | "Define fold range for `recipe' in Make.
1200 |
1201 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1202 | more information."
1203 | (when-let* ((last-child (treesit-fold-last-child node))
1204 | (beg (treesit-node-start node))
1205 | (end (treesit-node-end last-child)))
1206 | (treesit-fold--cons-add (cons beg end) offset)))
1207 |
1208 | (defun treesit-fold-range-markdown-heading (node offset)
1209 | "Define fold range for Markdown headings.
1210 |
1211 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1212 | more information."
1213 | (when-let* ((text (treesit-node-text node))
1214 | ((string-prefix-p "#" text))
1215 | (beg (treesit-node-start node))
1216 | (end (treesit-node-end node)))
1217 | (treesit-fold--cons-add (cons beg end) offset)))
1218 |
1219 | (defun treesit-fold-range-markdown-code-block (node offset)
1220 | "Define fold range for Markdown code blocks.
1221 |
1222 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1223 | more information."
1224 | (let* ((beg (1+ (treesit-node-start node)))
1225 | (end (1- (treesit-node-end node)))
1226 | (name (+ 2 (length
1227 | (or (treesit-node-text (treesit-node-child node 1))
1228 | "")))))
1229 | (treesit-fold--cons-add (cons beg end) (cons name -2) offset)))
1230 |
1231 | (defun treesit-fold-range-markdown-html-block (node offset)
1232 | "Define fold range for Markdown `html_block'.
1233 |
1234 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1235 | more information."
1236 | (let* ((beg (+ (treesit-node-start node) 2))
1237 | (end (- (treesit-node-end node) 3)))
1238 | (treesit-fold--cons-add (cons beg end) offset)))
1239 |
1240 | (defun treesit-fold-range-matlab-blocks (node offset)
1241 | "Define fold range for MATLAB blocks.
1242 |
1243 | Each block is delimited by a line starting with '%%'.
1244 | For arguments NODE and OFFSET, see function `treesit-fold-range-line-comment'
1245 | for more information."
1246 | (when (string-prefix-p "%%" (treesit-node-text node))
1247 | (let* ((beg (treesit-node-end node))
1248 | (end (or (save-excursion
1249 | (progn (goto-char beg)
1250 | (when (re-search-forward "^\s*\^L*%%" nil t)
1251 | (beginning-of-line)
1252 | (if (or (eq (char-after) ?\C-l)
1253 | (not (save-excursion (forward-line -1)
1254 | (eq (char-after) ?\C-l))))
1255 | (forward-line -1)
1256 | (forward-line -2))
1257 | (end-of-line) (point))))
1258 | (treesit-node-end (treesit-node-parent node)))))
1259 | (treesit-fold--cons-add (cons beg end) offset))))
1260 |
1261 | (defun treesit-fold-range-matlab-function (node offset)
1262 | "Define fold range for MATLAB function definitions.
1263 |
1264 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1265 | more information."
1266 | (when-let* ((named-node (or (treesit-node-child-by-field-name node "superclass")
1267 | (treesit-node-child-by-field-name node "properties")
1268 | (treesit-node-child-by-field-name node "methods")
1269 | (treesit-node-child-by-field-name node "function_arguments")
1270 | (treesit-node-child-by-field-name node "function_output")
1271 | (treesit-node-child-by-field-name node "name")))
1272 | (beg (treesit-node-end (treesit-node-next-sibling named-node)))
1273 | (end (treesit-node-end node)))
1274 | (treesit-fold--cons-add (cons beg end) offset)))
1275 |
1276 | (defun treesit-fold-range-matlab-statements (node offset)
1277 | "Define fold range for MATLAB statements.
1278 |
1279 | For arguments NODE and OFFSET, see function `treesit-fold-range-line-comment'
1280 | for more information."
1281 | (when-let* ((cur-node (treesit-node-at (point)))
1282 | (named-node (car (treesit-fold-find-children node "\n")))
1283 | (beg (treesit-node-start named-node))
1284 | (ins (append
1285 | (treesit-fold-find-children node "catch_clause")
1286 | (treesit-fold-find-children node "case_clause")
1287 | (treesit-fold-find-children node "otherwise_clause")
1288 | (treesit-fold-find-children node "elseif_clause")
1289 | (treesit-fold-find-children node "else_clause")
1290 | (treesit-fold-find-children node "end"))) ;; can include parts maybe
1291 | (end (treesit-node-start (car (treesit-fold-find-children node "end")))))
1292 | (when (string-suffix-p "clause" (treesit-node-type (treesit-node-parent cur-node)))
1293 | (if (or (equal (treesit-node-type cur-node) "otherwise")
1294 | (equal (treesit-node-type cur-node) "else"))
1295 | (setq beg (treesit-node-end cur-node))
1296 | (setq beg (treesit-node-end (treesit-node-next-sibling cur-node))))
1297 | (setq end (1- (treesit-node-end (treesit-node-parent cur-node)))))
1298 | (treesit-fold--cons-add (cons beg end) offset)))
1299 |
1300 | (defun treesit-fold-range-mermaid-diagram (node offset)
1301 | "Define fold range for any diagram in Mermaid.
1302 |
1303 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1304 | more information."
1305 | (when-let* ((first-child (treesit-node-child node 0))
1306 | (beg (treesit-node-end first-child))
1307 | (beg (treesit-fold--eol beg))
1308 | (end (treesit-node-end node)))
1309 | (treesit-fold--cons-add (cons beg end) offset)))
1310 |
1311 | (defun treesit-fold-range-mermaid-block (node offset)
1312 | "Define fold range for any block in Mermaid.
1313 |
1314 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1315 | more information."
1316 | (when-let* ((beg-bracket (car (treesit-fold-find-children node "{")))
1317 | (end-bracket (treesit-fold-last-child node))
1318 | (beg (treesit-node-end beg-bracket))
1319 | (end (treesit-node-start end-bracket)))
1320 | (treesit-fold--cons-add (cons beg end) offset)))
1321 |
1322 | ;;+ OCaml
1323 |
1324 | (defun treesit-fold-range-ocaml-comment (node offset)
1325 | "Define fold range for `comment'.
1326 |
1327 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1328 | more information."
1329 | (when-let* ((text (treesit-node-text node))
1330 | (beg (+ (if (string-prefix-p "(* " text) 2 3)
1331 | (treesit-node-start node)))
1332 | (end (- (treesit-node-end node) 2)))
1333 | (treesit-fold--cons-add (cons beg end) offset)))
1334 |
1335 | (defun treesit-fold-range-ocaml-module-definition (node offset)
1336 | "Define fold range for `module_definition'.
1337 |
1338 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1339 | more information."
1340 | (when-let*
1341 | ((module-binding (treesit-node-child node 0 t))
1342 | (body (treesit-node-child-by-field-name module-binding "body"))
1343 | ;; body is struct ... end
1344 | (beg (+ 6 (treesit-node-start body)))
1345 | (end (- (treesit-node-end node) 3)))
1346 | (treesit-fold--cons-add (cons beg end) offset)))
1347 |
1348 | (defun treesit-fold-range-ocaml-type-definition (node offset)
1349 | "Define fold range for `type_definition'.
1350 |
1351 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1352 | more information."
1353 | (when-let*
1354 | ((type-definition (treesit-node-child node 0 t))
1355 | (body (treesit-node-child-by-field-name type-definition "body"))
1356 | (text (treesit-node-text (treesit-node-child body 0)))
1357 | (beg
1358 | (if (string-equal "{" text)
1359 | (1+ (treesit-node-start body))
1360 | (treesit-node-end (treesit-node-prev-sibling body))))
1361 | (end
1362 | (if (string-equal "{" text)
1363 | (1- (treesit-node-end node))
1364 | (treesit-node-end node))))
1365 | (treesit-fold--cons-add (cons beg end) offset)))
1366 |
1367 | (defun treesit-fold-range-ocaml-value-definition (node offset)
1368 | "Define fold range for `value_definition'.
1369 |
1370 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1371 | more information."
1372 | (when-let*
1373 | ((let-binding (treesit-node-child node 0 t))
1374 | (body (treesit-node-child-by-field-name let-binding "body"))
1375 | (beg (treesit-node-end (treesit-node-prev-sibling body)))
1376 | (end (treesit-node-end node)))
1377 | (treesit-fold--cons-add (cons beg end) offset)))
1378 |
1379 | ;;- OCaml
1380 |
1381 | (defun treesit-fold-range-org-body (node offset)
1382 | "Define fold range for `body' in Org.
1383 |
1384 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1385 | more information."
1386 | (when-let*
1387 | ((parent (treesit-node-parent node))
1388 | (parent (treesit-node-parent parent)))
1389 | (treesit-fold--cons-add (cons -1 0) (treesit-fold-range-seq node offset))))
1390 |
1391 | (defun treesit-fold-range-pascal-comment (node offset)
1392 | "Define fold range for `comment' in Pascal.
1393 |
1394 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1395 | more information."
1396 | (let ((text (treesit-node-text node)))
1397 | (cond ((string-prefix-p "{" text)
1398 | (treesit-fold-range-seq node offset))
1399 | ((string-prefix-p "(*" text)
1400 | (treesit-fold-range-seq node (treesit-fold--cons-add '(1 . -1) offset)))
1401 | (t
1402 | (treesit-fold-range-c-like-comment node offset)))))
1403 |
1404 | (defun treesit-fold-range-python-block (node offset)
1405 | "Define fold range for `if_statement' and other blocks.
1406 |
1407 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1408 | more information."
1409 | (when-let* ((colon-node (car (treesit-fold-find-children node ":")))
1410 | (beg (treesit-node-start colon-node)))
1411 | (let ((current-node (treesit-node-next-sibling colon-node))
1412 | (last-body-node)
1413 | (end))
1414 | ;; Iterate through siblings until we hit an elif or else clause
1415 | (while (and current-node
1416 | (not (member (treesit-node-type current-node)
1417 | '("elif_clause" "else_clause" "except_clause"))))
1418 |
1419 | ;; Only consider non-comment nodes as body nodes
1420 | (unless (string-match-p "comment" (treesit-node-type current-node))
1421 | (setq last-body-node current-node))
1422 | (setq current-node (treesit-node-next-sibling current-node)))
1423 |
1424 | ;; Set end position based on the last body node or fallback to node end
1425 | (setq end (if last-body-node
1426 | (treesit-node-end last-body-node)
1427 | (treesit-node-end node)))
1428 |
1429 | ;; Return the range and offset to fold
1430 | (treesit-fold--cons-add (cons (+ beg 1) end) offset))))
1431 |
1432 | (defun treesit-fold-range-python-def (node offset)
1433 | "Define fold range for `function_definition' and `class_definition'.
1434 |
1435 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1436 | more information."
1437 | (when-let* ((named-node (or (treesit-node-child-by-field-name node "superclasses")
1438 | (treesit-node-child-by-field-name node "return_type")
1439 | (treesit-node-child-by-field-name node "parameters")
1440 | (treesit-node-child-by-field-name node "name")))
1441 | ;; the colon is an anonymous node after return_type or parameters node
1442 | (beg (treesit-node-end (treesit-node-next-sibling named-node)))
1443 | (end (treesit-node-end node)))
1444 | (treesit-fold--cons-add (cons beg end) offset)))
1445 |
1446 | (defun treesit-fold-range-python-expression-statement (node offset)
1447 | "Define fold range for `expression_statement'.
1448 |
1449 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1450 | more information."
1451 | (when-let* ((string-node (car (treesit-fold-find-children node "string")))
1452 | ;; the colon is an anonymous node after return_type or parameters node
1453 | (beg (treesit-node-start string-node))
1454 | (end (treesit-node-end node)))
1455 | (treesit-fold--cons-add (cons (+ beg 3) (- end 3)) offset)))
1456 |
1457 | (defun treesit-fold-range-rst-body (node offset)
1458 | "Define fold range for `body' in reStructuredText.
1459 |
1460 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1461 | more information."
1462 | (let* ((first (car (treesit-node-children node)))
1463 | (beg (treesit-node-end first))
1464 | (end (treesit-node-end node))
1465 | (same-pos (= beg end))
1466 | (beg (if same-pos (treesit-node-start node) beg)))
1467 | (treesit-fold--cons-add (cons beg end) offset)))
1468 |
1469 | (defun treesit-fold-range-ruby-class-def (node offset)
1470 | "Define fold range for `method' and `class' in Ruby.
1471 |
1472 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1473 | more information."
1474 | (when-let* ((named-node (or (treesit-node-child-by-field-name node "superclass")
1475 | (treesit-node-child-by-field-name node "parameters")
1476 | (treesit-node-child-by-field-name node "name")))
1477 | (beg (treesit-node-end named-node))
1478 | (end (treesit-node-end node))
1479 | (end (- end 3)))
1480 | (when treesit-fold-on-next-line ; display nicely
1481 | (setq end (treesit-fold--last-eol end)))
1482 | (treesit-fold--cons-add (cons beg end) offset)))
1483 |
1484 | (defun treesit-fold-range-ruby-if (node offset)
1485 | "Define fold range for `if' (then), `elsif', and `else' in Ruby.
1486 |
1487 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1488 | more information."
1489 | (when-let* ((beg (treesit-node-start node))
1490 | (end (cond ((when-let* ((next (treesit-node-next-sibling node)))
1491 | (treesit-node-start next)))
1492 | ((when-let* ((parent (treesit-fold-find-parent node "if")))
1493 | (- (treesit-node-end parent) 3))))))
1494 | (when treesit-fold-on-next-line ; display nicely
1495 | (setq end (treesit-fold--last-eol end)))
1496 | (treesit-fold--cons-add (cons beg end) offset)))
1497 |
1498 | (defun treesit-fold-range-rust-macro (node offset)
1499 | "Return the fold range for `macro_definition' in Rust.
1500 |
1501 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1502 | more information."
1503 | (when-let* ((last_bracket (treesit-fold-last-child node))
1504 | (first_bracket (treesit-node-child node 2))
1505 | (beg (treesit-node-start first_bracket))
1506 | (end (1+ (treesit-node-start last_bracket))))
1507 | (treesit-fold--cons-add (cons beg end) offset)))
1508 |
1509 | (defun treesit-fold-range-sql-block (node offset)
1510 | "Return the fold range for `block' in SQL.
1511 |
1512 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1513 | more information."
1514 | (when-let* ((beg-node (car (treesit-fold-find-children node "keyword_begin")))
1515 | (end-node (car (treesit-fold-find-children node "keyword_end")))
1516 | (beg (treesit-node-end beg-node))
1517 | (end (treesit-node-start end-node)))
1518 | (treesit-fold--cons-add (cons beg end) offset)))
1519 |
1520 | (defun treesit-fold-range-toml-table (node offset)
1521 | "Return the fold range for `table' in TOML.
1522 |
1523 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1524 | more information."
1525 | (when-let* ((close-bracket (car (treesit-fold-find-children node "]")))
1526 | (beg (treesit-node-end close-bracket))
1527 | (end-child (treesit-fold-last-child node))
1528 | (end (treesit-node-end end-child)))
1529 | (treesit-fold--cons-add (cons beg end) offset)))
1530 |
1531 | (defun treesit-fold-range-verilog-initial-construct (node offset)
1532 | "Return the fold range for `initial' in Verilog.
1533 |
1534 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1535 | more information."
1536 | (when-let* ((beg (treesit-node-start node))
1537 | (beg (treesit-fold--eol beg))
1538 | (end-child (treesit-fold-last-child node))
1539 | (end (treesit-node-end end-child))
1540 | (end (treesit-fold--bol end)))
1541 | (when treesit-fold-on-next-line
1542 | (setq end (treesit-fold--last-eol end)))
1543 | (treesit-fold--cons-add (cons beg end) offset)))
1544 |
1545 | (defun treesit-fold-range-verilog-list (node offset)
1546 | "Return the fold range for `list' in Verilog.
1547 |
1548 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1549 | more information."
1550 | (when-let* ((prev (treesit-node-prev-sibling node))
1551 | (next (treesit-node-next-sibling node))
1552 | (beg (treesit-node-end prev))
1553 | (end (treesit-node-start next)))
1554 | (treesit-fold--cons-add (cons beg end) offset)))
1555 |
1556 | (defun treesit-fold-range-verilog-module (node offset)
1557 | "Return the fold range for `module' in Verilog.
1558 |
1559 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1560 | more information."
1561 | (when-let* ((close-bracket (car (treesit-fold-find-children node ";")))
1562 | (beg (treesit-node-end close-bracket))
1563 | (end-child (treesit-fold-last-child node))
1564 | (end (treesit-node-end end-child))
1565 | (end (treesit-fold--bol end)))
1566 | (when treesit-fold-on-next-line
1567 | (setq end (treesit-fold--last-eol end)))
1568 | (treesit-fold--cons-add (cons beg end) offset)))
1569 |
1570 | (defun treesit-fold-range-vhdl-package (node offset)
1571 | "Return the fold range for `package' in VHDL.
1572 |
1573 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1574 | more information."
1575 | (when-let* ((start-child (car (treesit-fold-find-children node "declarative_part")))
1576 | (beg (treesit-node-start start-child))
1577 | (beg (treesit-fold--last-eol beg))
1578 | (end-child (car (treesit-fold-find-children node "end")))
1579 | (end (treesit-node-start end-child)))
1580 | (when treesit-fold-on-next-line
1581 | (setq end (treesit-fold--last-eol end)))
1582 | (treesit-fold--cons-add (cons beg end) offset)))
1583 |
1584 | (defun treesit-fold-range-vhdl-type (node offset)
1585 | "Return the fold range for `type' in VHDL.
1586 |
1587 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1588 | more information."
1589 | (when-let* ((start-child (car (treesit-fold-find-children node "record_type_definition")))
1590 | (record (car (treesit-fold-find-children start-child "record")))
1591 | (beg (treesit-node-end record))
1592 | (end-child (car (treesit-fold-find-children start-child "end")))
1593 | (end (treesit-node-start end-child)))
1594 | (when treesit-fold-on-next-line
1595 | (setq end (treesit-fold--last-eol end)))
1596 | (treesit-fold--cons-add (cons beg end) offset)))
1597 |
1598 | (defun treesit-fold-range-vimscript-function (node offset)
1599 | "Return the fold range for `function!' and `func' NODE
1600 | in Vimscript.
1601 |
1602 | For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
1603 | more information."
1604 | (when-let* ((param-node (treesit-node-child node 1))
1605 | (beg (treesit-node-start param-node))
1606 | (end (treesit-node-end node)))
1607 | (unless treesit-fold-on-next-line ; display nicely
1608 | (setq beg (treesit-fold--last-eol beg)))
1609 | (treesit-fold--cons-add (cons beg end) offset)))
1610 |
1611 | (provide 'treesit-fold)
1612 | ;;; treesit-fold.el ends here
1613 |
--------------------------------------------------------------------------------