Compare commits

...

434 commits

Author SHA1 Message Date
Christian Clason
4916d6592e fix(health): normalize rtp when checking install_dir
Problem: Windows.

Solution: vim.fs.normalize.
2026-04-03 15:11:40 +02:00
Christian Clason
234d76709e ci(tests): remove ilammy/msvc-dev-cmd
Problem: Action uses deprecated Node 20, and Windows runners have a
current msvc build tools by default.

Solution: Remove action.
2026-04-03 14:38:57 +02:00
Christian Clason
2098db61dc fix(yuck): improper use of supertypes in queries
Problem: `(ast_block)` is a supertype, of which `(symbol)` (among
others) is a subtype, which makes the final local pattern invalid.
(This was not noticed before because the parser is stuck at ABI 14
due to a missing `tree-sitter.json`.)

Solution: Fix the pattern and use supertype where appropriate.
2026-04-03 14:23:36 +02:00
Riley Bruins
81295eb0c5
feat(parsers): add jjdescription (#8625) 2026-04-03 10:43:28 +02:00
Christian Clason
539abf6da5 chore: remove redundant emmyluarc entry 2026-04-02 19:03:52 +02:00
Christian Clason
6878ae017d ci: migrate to emmyluals 2026-04-02 15:00:21 +02:00
Christian Clason
c82bf96f0a feat!: drop support for Nvim 0.11 2026-04-01 14:59:03 +02:00
Christian Clason
90cd6580e7 tests: add stable Nvim 2026-04-01 14:59:03 +02:00
nvim-treesitter-bot[bot]
7caec274fd bot(parsers): update beancount, gotmpl, heex, helm, idl, javadoc, jinja, jinja_inline, just, kotlin, liquid, mlir, ocaml, ocaml_interface, pkl, pod, rust, supercollider, typoscript 2026-03-28 07:33:46 +00:00
Riley Bruins
da8bf82a53
fix(kotlin): regex and printf injections not applying (#8613) 2026-03-27 15:22:25 -07:00
Riley Bruins
f059649bc3
fix(go): highlight rune as @character (#8612) 2026-03-27 11:37:59 -07:00
Adrian Wang
6620ae1c44
fix(install): use rename-before-unlink on all platforms
Problem: On macOS Apple Silicon, a plain unlink can leave stale code
signature metadata in the kernel cache, causing SIGKILL on next page
fault after `TSUpdate`.

Solution: Apply the rename-then-unlink strategy unconditionally instead
of only on Windows.
2026-03-23 10:32:51 +01:00
Christian Clason
8755152551
fix(parsers): track default branch for perl, pod (#8605)
Problem: non-default "release" branch tracking is broken, but the
default branch contains grammar.json.

Solution: track default `main` branch and generate parser from JSON.
2026-03-22 16:49:17 +00:00
Christian Clason
0e0db770f2 fix(parsers): don't specify default branch 2026-03-22 12:20:33 +01:00
nvim-treesitter-bot[bot]
e5f65e31a5 bot(parsers): update arduino, c3, cue, dart, fortran, fsharp, git_rebase, gleam, heex, idl, just, kotlin, ledger, mlir, nim, nu, php, php_only, powershell, proto, racket, rust, scheme, swift, vhdl 2026-03-21 07:17:33 +00:00
dependabot[bot]
877f724846 ci: bump actions/create-github-app-token in the actions group
Bumps the actions group with 1 update: [actions/create-github-app-token](https://github.com/actions/create-github-app-token).


Updates `actions/create-github-app-token` from 2 to 3
- [Release notes](https://github.com/actions/create-github-app-token/releases)
- [Commits](https://github.com/actions/create-github-app-token/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/create-github-app-token
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-20 17:42:48 +01:00
Christian Clason
53f6ce29df feat(zsh)!: update parser and queries 2026-03-20 10:43:21 +01:00
Christian Clason
2b50ab5ccb test: replace plenary with plentest.nvim
Problem: plenary.nvim as test runner is overkill and no longer
maintained.

Solution: Replace with a minimal fork based on Neovim API and vendored
luassert.
2026-03-17 18:20:03 +01:00
Christian Clason
2cc172c28e test(indent): we have scan_dir at home 2026-03-17 09:47:15 +01:00
Christian Clason
c9fea86a5a test(indent): drop plenary.path 2026-03-16 22:51:41 +01:00
George Harker
b9f9d692f1
feat(zsh): update parser and queries
add `;|` highlighting
2026-03-16 20:08:58 +01:00
Christian Clason
ebc3201290 fix(zsh): mark as tier 2 2026-03-16 10:03:08 +01:00
Christian Clason
2f5d4c3f3c docs(readme): clarify pre-release support policy 2026-03-14 19:46:07 +01:00
Christian Clason
f873ec2955 refactor(config): no trailing slash in installdir 2026-03-14 19:19:10 +01:00
Luca Papagni
88a217f570
Show errors on vim.system failure (#8552)
Problem: `vim.system` throws an error when `uv.spawn` fails, in
particular when `cmd` or `cwd` does not exist. This kills the coroutine,
which makes the corresponding async call hang.

Solution: Wrap `vim.system` in a function that catches any error and
returns it as `stderr` in a `SystemObj`.

Co-authored-by: Christian Clason <c.clason@uni-graz.at>
2026-03-14 19:06:38 +01:00
nvim-treesitter-bot[bot]
eb1f8e80cb bot(parsers): update c3, elixir, erlang, fsharp, gitcommit, hyprlang, kotlin, ledger, pkl, powershell, proto, ruby, scala, scheme, t32, v 2026-03-14 07:15:51 +00:00
Riley Bruins
493890b87a feat(textproto): punctuation and string escape highlights 2026-03-12 09:28:44 +01:00
Christian Clason
5cb05e1b0f fix(filetype): don't register c-sharp
Language names can only contain hyphens, and dashes are normalized by
Nvim itself now.
2026-03-07 11:15:38 +01:00
nvim-treesitter-bot[bot]
4110daee15 bot(parsers): update blade, elixir, gitcommit, groovy, idl, javadoc, kotlin, liquidsoap, matlab, nu, pkl, proto, t32, vhdl 2026-03-07 09:33:18 +00:00
nvim-treesitter-bot[bot]
9fd4d998c3 bot(parsers): update wit, zsh 2026-03-07 10:32:48 +01:00
Stefan VanBuren
ebe76eb800
feat(proto): sync queries with upstream (#8554)
This adds support for [Protobuf Editions][1], and a couple other minor
fixes.

Ref: https://github.com/coder3101/tree-sitter-proto/tree/main/queries

[1]: https://protobuf.dev/editions/overview/
2026-03-06 16:12:43 +00:00
Christian Clason
1970f0d3bb feat(robot)!: update parser and queries
Breaking change: replaced `(variable_definition)` by
`(scalar_variable)`, `(list_variable)` and `(dictionary_variable)`.

Also mark queries as unmaintained.
2026-03-06 11:04:36 +01:00
elgiano
544320a9cf feat(supercollider)!: update parser and queries
parser PR: https://github.com/madskjeldgaard/tree-sitter-supercollider/pull/67

removed nodes:
control_structure, if, while, for, forby, method_call,
method_name, instance_variable_setter_call, argument_calls

added nodes:
class_def_body, !==, ===

modified nodes:
function_call now has fields receiver, name and arguments
chained method calls now appear as nested function_calls (where receiver
is another function_call)
2026-03-04 12:35:03 +01:00
Christian Clason
972f378653 fix(config): normalize default install_dir
Problem: The default `install_dir` is not normalized, leading to a
false positive checkhealth failure when comparing against the normalized
`runtimepath` directories.

Solution: Use trailing slash in default `install_dir`.
2026-03-03 19:25:06 +01:00
Riley Bruins
cb2cb74f3c feat(nickel): many more highlights 2026-03-01 22:56:47 +01:00
Ethan Rutt
995b75fd51
feat: add gql function highlighting for ecmascript injection (#8541) 2026-03-01 13:29:06 -08:00
nvim-treesitter-bot[bot]
6bc51d020a bot(parsers): update blade, kotlin, liquidsoap, lua, markdown, markdown_inline, mlir, proto, unison, vim 2026-02-28 07:10:54 +00:00
Igor
ae2081cfcd feat(ecma): variable definition from object destructure with alias 2026-02-27 09:00:07 +01:00
Tomas Sandven
b9171ede5d
feat(robot): update parser, mark as stable 2026-02-26 20:17:27 +01:00
nvim-treesitter-bot[bot]
957f86ae3f bot(parsers): update zsh 2026-02-26 11:17:02 +01:00
nvim-treesitter-bot[bot]
8ada222612 bot(parsers): update cpp, cue, fish, groovy, julia, liquid, lua, markdown, markdown_inline, mlir, pkl, powershell, query, slint, sql, swift, systemverilog, vhdl, vim 2026-02-26 10:06:44 +00:00
Christian Clason
eaa5caed2a feat(make): update parser and queries 2026-02-26 10:45:02 +01:00
Ilya Ilyinykh
0f5b204603
fix(typst): indentation for block and branch 2026-02-25 18:35:46 +01:00
Omar Valdez
67d0fd3e0a feat(xresources,desktop): mark as tier 1 2026-02-25 15:40:58 +01:00
Salomon Popp
c6d295e966
feat(nickel): update highlight queries to grammar changes 2026-02-25 10:06:48 +01:00
Ark1409
a8845121f0
fix(c_sharp): missing highlight for lambda modifier (#8526) 2026-02-24 18:25:39 -08:00
Omar Valdez
d660b7c002 feat(editorconfig)!: update parser and queries
Removed nodes:
section_name, expansion_string, wildcard_characters,
wildcard_any_characters, wildcard_single_character, unset, boolean,
spelling_language, indent_style, end_of_line, charset, unknown

Renamed nodes:
identifier -> property
negation -> "!"
path_separator -> "/"
escaped_character -> character_escape
2026-02-23 17:49:34 +01:00
nvim-treesitter-bot[bot]
dc42c209f3 bot(parsers): update c_sharp, desktop, editorconfig, fish, kitty, kotlin, mlir, proto, rescript, sql, swift, xresources 2026-02-21 07:10:10 +00:00
Christian Clason
fcd51bbe92 fix(supercollider): mark as tier 3 2026-02-20 11:08:31 +01:00
Robert Muir
3edb01f912
fix(install): unlink files before copy on unix to prevent crashes (#8517)
uv_fs_copyfile will truncate the target first, which can result in
hard-to-debug crashes if the shared object is currently in use.

instead, unlink the target first, so that the operation doesn't modify
any in-use files. the disk space from the old parsers won't be reclaimed
until any processes using them relinquish their open file handles.
2026-02-19 15:39:22 +01:00
Christian Clason
ecdae44bae feat(kotlin)!: update parser and queries
Breaking change: removed nodes `"!in"` and `"!is"`.
2026-02-18 19:53:54 +01:00
NullVoxPopuli
23502d650a
fix(glimmer_typescript): inherit typescript indents 2026-02-18 17:32:57 +01:00
Stefan VanBuren
0211563445
feat(protobuf)!: switch parser repo (#8514)
This switches the protobuf parser to https://github.com/coder3101/tree-sitter-proto,
which is a maintained parser and used in Zed.

The old https://github.com/treywood/tree-sitter-proto is effectively
unmaintained AFAICT, so it would be nice to have a maintained repo here.
2026-02-18 16:26:40 +00:00
nvim-treesitter-bot[bot]
2bd9b9b4f1 bot(parsers): update angular, bpftrace, c_sharp, fortran, markdown, markdown_inline, mlir, nickel, tlaplus 2026-02-17 17:02:40 +00:00
Dennis van den Berg
ca35dc5184 feat(angular): adds support for css class bindings 2026-02-17 14:56:12 +01:00
Christian Clason
4d9466677a fix(install): raise number of retries
Seven retries ought to be enough for anybody.
2026-02-14 13:18:48 +01:00
fin-w
b032f66f0b
fix(health): consistent abbreviations in legend 2026-02-14 12:33:04 +01:00
nvim-treesitter-bot[bot]
88a8487378 bot(parsers): update dart, fortran, gleam, janet_simple, just, mlir, rescript, slint, solidity, sql, t32, unison 2026-02-14 11:19:53 +00:00
Christian Clason
9f2dad22ef feat(vento)!: update parser and queries
Breaking change: `(keyword)` node removed.

Also mark as unmaintained (Copilot-maintained)
2026-02-11 12:14:00 +01:00
nvim-treesitter-bot[bot]
45a07f869b bot(parsers): update javadoc, just, kotlin, markdown, markdown_inline, matlab, mlir, php, php_only, pkl, slint, unison 2026-02-07 07:11:42 +00:00
Christian Clason
92c9b016d1 fix(install): retry on server error 2026-02-06 12:16:51 +01:00
phanium
70a9fecaf5 fix(lua): injections in vim.{rpcrequest,rpcnotify} 2026-02-05 09:15:56 +01:00
nvim-treesitter-bot[bot]
4967fa48b0 bot(parsers): update beancount, c3, dart, desktop, editorconfig, gap, jinja, jinja_inline, matlab, mlir, nu, pkl, swift, unison, xresources, yaml 2026-01-31 10:18:44 +00:00
Christian Clason
ac1d0ff910 fix(scripts): guard against empty reply when checking new revisions 2026-01-31 11:07:03 +01:00
Christian Clason
19c729dae6 fix(install)!: remove gitlab codepath
Gitlab tarballs have started including the commit hash, so downstream
processing fails anyway.
2026-01-29 16:22:32 +01:00
Christian Buttner
04ab807f8e
feat(c3)!: update parser and highlights (#8477)
Breaking: `(import_declaration (path_ident))` changed to `(import_path (path_ident))`
2026-01-29 10:02:30 +00:00
stefan
cc12e37e5b fix(nix): make all bash injections combined 2026-01-29 10:41:43 +01:00
Christian Clason
5465196ba8 fix(health): update required tree-sitter version 2026-01-29 10:29:15 +01:00
Christian Clason
f8bbc3177d feat(roc): mark as unmaintained 2026-01-27 12:02:53 +01:00
Christian Clason
0ac55b85c6 refactor(lua): replace vim.opt with vim.o 2026-01-27 11:57:04 +01:00
nvim-treesitter-bot[bot]
568ede7e79 bot(parsers): update ruby, vue 2026-01-25 11:08:41 +00:00
Bartłomiej Maryńczak
81aca2f981
feat(rust): add !xml injection 2026-01-24 22:21:27 +01:00
NullVoxPopuli
67b3ce0529
fix(glimmer) update injections 2026-01-24 22:21:10 +01:00
nvim-treesitter-bot[bot]
275b9fe801 bot(parsers): update zsh 2026-01-24 10:58:14 +01:00
nvim-treesitter-bot[bot]
b67d29ce74 bot(parsers): update c_sharp, desktop, dtd, editorconfig, fennel, fortran, hcl, javadoc, just, lalrpop, lua, markdown, markdown_inline, meson, mlir, rescript, rifleconf, sql, swift, terraform, tlaplus, vim, xml, xresources 2026-01-24 07:03:36 +00:00
Stanislaw Gruszka
88f1dfc211 feat(bpftrace): update parser and small highlights improvements
Update parser. Use new builtins from grammar (don't use lua-match).
2026-01-23 10:52:33 +01:00
Christian Clason
511e5ccf40 ci: correct concurrency group for downstream 2026-01-22 18:44:49 +01:00
Christian Clason
62dad2a60a ci: add concurrency for downstream tests 2026-01-22 18:36:56 +01:00
Christian Clason
61d3f5b186 test(lint): bump luals to 3.17.1 2026-01-22 18:36:56 +01:00
Christian Clason
0d1b8b026b ci: use ubuntu-slim for small jobs 2026-01-22 18:36:56 +01:00
mintbug
ec03481377 feat(typst): set url attribute for links 2026-01-20 16:01:54 +01:00
Peter Cardenas
e75c007f27 fix(fish): update builtin highlights 2026-01-19 17:36:05 +01:00
Christian Clason
b9933f0e13 test(init): remove upstreamed Tiger ft detection 2026-01-19 10:37:35 +01:00
Mariusz Biegański
d9a5fb8484 docs(supported_languages): fix order of available queries 2026-01-18 17:34:33 +01:00
Christian Clason
3121570f07 docs(contributing): inclusion criteria 2026-01-18 17:31:30 +01:00
Christian Clason
d19def46c1 fix(make): switch to maintained fork 2026-01-17 16:15:39 +01:00
Nico Salm
19261d56ed fix(rust): highlight doc comment markers as @comment.documentation
Co-authored-by: LunarLambda <LunarLambda@users.noreply.github.com>
2026-01-17 12:12:37 +01:00
nvim-treesitter-bot[bot]
7c14161403 bot(parsers): update bpftrace, desktop, editorconfig, glimmer, javadoc, liquidsoap, markdown, markdown_inline, matlab, meson, mlir, nim, pkl, rego, rescript, swift, vhdl, xresources 2026-01-17 06:56:25 +00:00
Abbath
8aada0e394 fix(haskell): use grammar for operator detection instead of match 2026-01-16 18:11:27 +01:00
Abbath
15b3416cc1 fix(haskell): highlighting for operator definition and operator-like constructors. 2026-01-15 09:19:05 +01:00
Abbath
c872ec85cc fix(haskell): syntax highlighting for Haskell lambda expressions
Fixes highlighting for lambdas with multiple parameters.
2026-01-15 09:19:05 +01:00
nvim-treesitter-bot[bot]
5a7e5638e7 bot(parsers): update inko 2026-01-10 10:39:10 +01:00
nvim-treesitter-bot[bot]
6016f1232d bot(parsers): update beancount, bpftrace, c3, fortran, gleam, lua, mlir, sql 2026-01-10 06:57:05 +00:00
Christian Clason
2ba5ec1846 test(init): remove upstreamed Nickel ft detection 2026-01-08 10:34:30 +01:00
Riley Bruins
5e8652dbaf fix(usd): misc punctuation highlights 2026-01-08 10:17:12 +01:00
Stanislaw Gruszka
9177f2ff06
feat(parsers): add bpftrace (#8399)
Co-authored-by: Riley Bruins <ribru17@hotmail.com>
2026-01-07 21:59:10 -08:00
Chris Dragan
6feaebb456
feat(kos): highlights improvements (#8404)
* Mark floats as number.float
* Mark function arguments as variable.parameter
* Mark _ placeholder as character.special
* Mark string interpolation delimiters as punctuation.special
2026-01-07 21:53:42 -08:00
Igor Lacerda
de878155ca
fix(html_tags): disable spell for tags (#8410)
When tags are embedded into markdown, they'd get spell checked, in spite
of that not really making sense. The real culprit of this issue is
markdown's spell being too "loose".
2026-01-07 16:39:29 +01:00
Farid
b033ab331c docs(readme): fix lazy snippet 2026-01-05 12:01:59 +01:00
Christian Clason
99dfc5acef docs(readme): fix lazy snippet 2026-01-04 18:08:46 +01:00
Chris Dragan
31fc7e10cd
feat: add kos parser and queries (#8389) 2026-01-04 11:08:07 +01:00
PolarMutex
300b906a95
fix(beancount): update to windows-compatible version (#8401) 2026-01-03 18:15:14 +01:00
Sten Laane
4337799162 feat(bash): add indents query
It's pretty basic at the moment but already makes working with bash
scripts way easier.
2026-01-03 11:29:39 +01:00
neno
86cf4fb684 fix(ruby): improve highlights for pattern matching and for...in loops 2026-01-03 11:28:41 +01:00
nvim-treesitter-bot[bot]
46c16d89a8 bot(parsers): update c3, desktop, editorconfig, javadoc, kitty, lua, nginx, query, swift, templ, typespec, v, vim, xresources 2026-01-03 10:20:31 +00:00
Daniel Jakots
737088f857
docs(languages): remove unused node legend (#8396)
erroneously reintroduced in 69c76488f7.
2026-01-02 15:37:00 +00:00
Christian Clason
1927c76aec feat(install): warn on unsupported parsers 2026-01-02 10:04:03 +01:00
Christian Clason
efa5d1fa3a feat(robots)!: adapt to renamed parser 2026-01-02 10:02:25 +01:00
Christian Clason
c6dd314086 fix(lua): re-add missing assignment operator 2025-12-31 15:21:31 +01:00
Christian Clason
d6ce707613 feat(lua): replace operator list with field 2025-12-31 13:57:06 +01:00
Marc Jakobi
7efc1b58a8
fix(nix): refactor nixosTest injections for better performance (#8378) 2025-12-29 16:47:03 +01:00
nvim-treesitter-bot[bot]
36fcb4a423 bot(parsers): update desktop, editorconfig, erlang, gotmpl, helm, lua, mlir, pascal, sql, typoscript, v, xresources 2025-12-27 06:56:45 +00:00
Marc Jakobi
45d08da7bb chore(nix): add mrcjkb to maintainers 2025-12-26 22:13:05 +01:00
Marc Jakobi
7ba26e7685 perf(nix): replace match with lua-match 2025-12-26 22:13:05 +01:00
Christian Clason
6e42d823ce fix(strace): no longer need to generate 2025-12-21 15:27:47 +01:00
Christian Clason
8cdffc6d33 feat(vim): support :tab command 2025-12-20 12:40:15 +01:00
Christian Clason
f795520371 fix(strace): generate removed parser 2025-12-20 12:36:44 +01:00
nvim-treesitter-bot[bot]
e08ad49dbd bot(parsers): update editorconfig, meson, mlir, phpdoc, t32, vhdl 2025-12-20 06:55:48 +00:00
Christian Clason
4fc09bee78 ci(dependabot): fix labels 2025-12-17 13:12:25 +01:00
dependabot[bot]
cfdca13a5d ci: bump the actions group with 2 updates
Bumps the actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request).


Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

Updates `peter-evans/create-pull-request` from 7 to 8
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: peter-evans/create-pull-request
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-17 13:00:42 +01:00
Christian Clason
fc21d3db8c ci: add dependabot for GH actions 2025-12-17 12:55:05 +01:00
Christian Clason
846c7b50ee chore: remove FUNDING.yml 2025-12-17 12:55:05 +01:00
Christian Clason
d0bf5ff2b0 feat(parsers): update ada, c3, comment, desktop, editorconfig, elm, julia, mlir, nu, phpdoc, t32, tera, vim, vimdoc, xresources, zsh 2025-12-17 11:53:39 +01:00
Manfred Egger
568f2a3b7d
feat(typoscript)!: update grammar and queries (#8341)
Breaking change: `(condition_bool)` renamed to `(condition_bool_legacy)`
2025-12-17 11:48:06 +01:00
Christian Clason
d3218d988f docs(readme)!: main is now the default branch 2025-12-14 13:16:25 +01:00
Christian Clason
74b119812e feat(gleam)!: update parser and queries
Breaking change: `(bit_string_*)` renamed to `(bit_array_*)`
2025-12-13 14:28:41 +01:00
Christian Clason
74d3999522 feat(parsers): update fortran, gotmpl, helm, idl, mlir, pkl, query, racket, scheme, slint, vhdl, zsh 2025-12-13 14:21:32 +01:00
Christian Clason
2979e048b3 ci(test): bump tree-sitter/setup-actions to v2 2025-12-11 10:57:07 +01:00
Marc Jakobi
b6271b678e feat(haskell): injection for morpheus-graphql-client quasiquotes 2025-12-09 11:02:20 +01:00
Riad
186810d6ad feat(gdscript): update builtin highlights
Added all builtin annotations, constants, methods
and types as of godot commit : 10c7cb8
2025-12-09 11:01:36 +01:00
adaitche
02693ce64c
feat(sql): improve @type capture (#8315)
Problem: `@type` currently captures function calls but fails to
capture CTE names.

Solution: Don't capture types in invocations. Add pattern for `cte`.
2025-12-09 10:53:37 +01:00
Christian Clason
a98a740c55 feat(parsers): update brightscript, desktop, gotmpl, helm, ini, javadoc, mlir, nu, powershell, slint, vimdoc, xresources 2025-12-09 10:19:54 +01:00
Omar Valdez
f47f549f74 feat(bash): highlight arguments of trap and kill builtin commands 2025-12-08 14:47:59 +01:00
Omar Valdez
93537d6998 feat(bash): remove unnecessary captures
- Bash does not have boolean values and the builtin `true`
  and `false` commands are already covered by another capture.
- The grammar has a `number` node and it's already captured.
2025-12-08 13:08:03 +01:00
Cameron
bfc6c99540
fix(ruby): highlighting for string-literal symbols (#8317) 2025-12-08 11:27:09 +01:00
Yorick Peterse
20db421f5f
feat(inko): update to v0.4.0 (#8327)
This changes the structure of "if" expressions so the queries for
nvim-treesitter-textobjects can be changed as to not cause any crashes.
2025-12-06 22:38:22 +01:00
Christian Clason
9d47b2558b feat(json): add support for jsonc files 2025-12-06 18:10:39 +01:00
Christian Clason
d2350758b3 feat(parsers)!: remove gitlab-hosted blueprint, fusion, jsonc
Problem: Gitlab has too frequent outages, which break automation.

Solution: Drop all Gitlab-hosted parsers (two of which have been
unmaintained for years).
2025-12-06 18:10:39 +01:00
Christian Clason
d72fa25b54 feat(fortran)!: update parser and queries
Breaking change: `(do_loop_statement)` renamed to `(do_loop)`
2025-12-06 14:13:26 +01:00
Christian Clason
41913a8d44 feat(bash): update parser
Breaking change: removed double parenthesis as valid opening to
arithmetic expansion. (Only `$((` is allowed according to the manual.)
2025-12-06 14:04:19 +01:00
Christian Clason
596923959a fix(inko): downgrade parser
Problem: The commit fc37d05c36 broke parsing a textobjects query.

Solution: Downgrade parser to previous commit and pin it (until we can move it to tier 1).
2025-12-06 13:29:48 +01:00
Christian Clason
6f2121231a feat(parsers): update angular, c3, desktop, elm, forth, inko, mlir, nix, pkl, powershell, templ, xresources 2025-12-06 13:09:06 +01:00
Christian Clason
e0eec76dad fix(lua): fix some emmyluals warnings 2025-12-06 11:16:30 +01:00
Dennis van den Berg
75797cdd8a
feat(angular): add style_unit highlighting(#8312) 2025-12-04 10:42:01 +01:00
Alexei Mozaidze
857fb97bb6 fix(fennel): highlight $[1-9] in multi-symbol context properly
Highlights the dollar symbol properly in multi-symbol contexts, like `$3.some.properties`.
There was already a fix for a similar issue on #8067, but it only addressed `$.some.properties`, but not the variant with the argument number in it.
2025-12-03 17:49:36 +01:00
Gabriel Holodak
c5623d3486
docs: document setting foldmethod alongside foldexpr (#8187) 2025-12-02 17:15:52 -08:00
nsfisis
e527584cf8
feat(vhs): update options list (#8309) 2025-12-02 12:03:33 -08:00
George Harker
00c906abb9
fix(zsh): update posix shell variables 2025-12-01 08:46:21 +01:00
Christian Clason
17885756e6 feat(parsers): update angular, c3, desktop, editorconfig, elm, gdshader, gleam, haskell, idl, php, php_only, pkl, query, readline, vimdoc, xresources 2025-11-27 18:54:20 +01:00
Tayfun Bocek
d56ed0f7f9
feat(gdshader): update highlight queries (#8299)
* use uniform scope node instead of literal matching

This avoids the need to refactor if other scope types are added. Maybe
helps performance as well.

* add method expression highlight
2025-11-27 10:35:21 +01:00
Christian Clason
c5871d9d87 fix(perl): correct use of supertypes 2025-11-25 10:40:58 +01:00
Christian Clason
d6ebbd5039 fix(haskell): correct use of supertypes in (decl) patterns
Problem: These patterns were impossible, since children need to be children of
every subtype of a supertype to be captured in this way. As subtypes
could appear as children themselves, the query code silently "skipped
over" the supertype restriction in the pattern. This was fixed in
tree-sitter v0.26.0, which now (correctly) flags these patterns as
"impossible".

Solution: Add the appropriate child nodes explicitly.
2025-11-25 10:28:33 +01:00
Christian Clason
3bbae7b32e feat(parsers): update angular, ini, json5, koto, matlab, mlir, nix, pkl, query, sql, t32, vimdoc, zsh 2025-11-23 13:31:11 +01:00
Christian Clason
bb83a67612 fix(fsharp): correct use of supertypes in (_type) patterns
Problem: These patterns were impossible, since children need to be children of
every subtype of a supertype to be captured in this way. As subtypes
could appear as children themselves, the query code silently "skipped
over" the supertype restriction in the pattern. This was fixed in
tree-sitter v0.26.0, which now (correctly) flags these patterns as
"impossible".

Solution: Add the appropriate child nodes explicitly.
2025-11-19 11:03:04 +01:00
Christian Clason
c682a239a9 feat(parsers): update asm, c_sharp, csv, desktop, gdshader, gotmpl, haskell, heex, helm, javadoc, matlab, mlir, pkl, psv, t32, tsv, xresources 2025-11-17 11:17:13 +01:00
Christian Clason
3a48d16c95 fix(ziggy): mark as unmaintained 2025-11-17 11:12:09 +01:00
Mikhail Katychev
69c76488f7
feat(wit)! update parser and queries to 1.2.0 (#8199) 2025-11-17 10:06:00 +00:00
Christian Clason
0cfa599474 chore: remove format-queries script
The source of truth for formatting (according to make formatquery and
 CI) is now ts_query_ls, so remove the no longer required script to
 prevent divergence and bitrotting.
2025-11-14 22:58:12 +01:00
Tomohiro Hashidate
2696fb8326
feat(ruby): update queries to support rbs-inline syntax (#8282) 2025-11-14 07:04:54 -08:00
George Harker
2144e88dac
feat(zsh): bump parser, disallow injections for regex with expansion 2025-11-13 15:20:34 -08:00
Derek Stride
0427eeb385
feat(sql): update parser, highlights (#8272) 2025-11-13 15:15:19 -08:00
Christoph Sax
b50774079a
feat(t32)!: update parser and queries (#8276)
`trace32_hll_variable` has been removed from the grammar. The
queries are now capturing `symbol` instead. `symbol` is highlighted
as variable or constant.
2025-11-12 10:06:04 +01:00
Tayfun Bocek
f46e3a09bd
fix(gdshader): add missing keyword to group (#8274) 2025-11-10 23:21:29 -08:00
Christian Clason
0a6817bcbb feat(haskell): switch to maintained fork 2025-11-10 23:15:20 +01:00
Christian Clason
81aec1e45d ci: add check for downstream queries
Problem: Parser updates may break downstream queries.

Solution: Add workflow that clones and validates queries in

* https://github.com/nvim-treesitter/nvim-treesitter-textobjects#main
* https://github.com/nvim-treesitter/nvim-treesitter-context

on changes to the parsers.lua table. (Workflow should not be required to
pass; the purpose is to give a heads-up that follow-up PRs are needed.)
2025-11-10 11:32:04 +01:00
Christian Clason
d97d226cfd feat(parsers): update asm, devicetree, gdshader, hack, hyprlang, koto, matlab, mlir, nix, ocamllex, pkl, sql, templ, zsh 2025-11-08 11:55:40 +01:00
Jaehwang Jung
5eca61b32a fix(python): nospell for interpolation 2025-11-06 12:35:06 +01:00
George Harker
1ddb266477
feat(parsers): add zsh support (#8240)
Co-authored-by: Christian Clason <c.clason@uni-graz.at>
Co-authored-by: Riley Bruins <ribru17@hotmail.com>
Co-authored-by: Tayfun Bocek <tayfunbocek@live.ca>
2025-11-05 20:13:53 -08:00
Alexey Svirshchevskiy
896e92a7f6
fix(typescript): support type param for styled components (#8066) 2025-11-04 20:07:27 -08:00
Igor Lacerda
53049d6678
feat(ecma): variable definition from object destructure (#8233) 2025-11-04 20:03:42 -08:00
Izzy Muerte
65a266bf69
fix(xml): remove CDATA injection
This change does not break existing injections that currently ship with nvim-treesitter, but instead allows additional injections to be defined by users, like those found in the Max/MSP Jitter XML Shader format.
2025-11-03 09:37:30 +01:00
Christian Clason
55820833a3 feat(parsers): update angular, desktop, earthfile, editorconfig, gdshader, javadoc, matlab, mlir, pkl, powershell, xresources 2025-11-02 10:47:45 +01:00
Tayfun Bocek
64f4755b9d
feat!(gdshader): replace gdshader parser and queries (#8244)
Switch parser to https://github.com/airblast-dev/tree-sitter-gdshader
2025-10-30 14:59:19 +01:00
Christian Clason
fd2880e8bc feat(install): remove node requirement
* supported parsers _must_ commit at least `grammar.json`
* set `TREE_SITTER_JS_RUNTIME=native` when generating parser to use
  built-in quickjs instead of node (requires tree-sitter 0.26)
2025-10-30 08:36:00 +01:00
Christian Clason
a3b489680f feat(scfg): update parser 2025-10-30 08:36:00 +01:00
Riley Bruins
2c30e515eb
fix: prefer #eq? for checking equality with one string (#8246) 2025-10-30 10:51:42 +09:00
Christian Clason
9ddd853e7e feat(diff): update parser after move 2025-10-29 19:32:05 +01:00
Christoph Horn
645f42e85d
feat(julia)!: update parser and queries (#8235)
sync locals queries with upstream

---------

Co-authored-by: Christian Clason <c.clason@uni-graz.at>
2025-10-27 10:43:58 +00:00
imawaki
738d9ced4c
feat(apex): javadoc injections (#8232)
Apex codebases commonly use Javadoc-style comments, similar to Java (Apex is Salesforce's object-oriented language).

This updates the injection query to capture javadoc nodes instead of the generic comment for better highlighting and parsing accuracy.
2025-10-26 19:07:19 +01:00
Lev Velykoivanenko
c53bb10a71
fix(python): regex injection not working for concatenated strings (#8197)
Co-authored-by: Riley Bruins <ribru17@hotmail.com>
2025-10-26 09:25:42 -07:00
Christian Clason
98fe644cb3 feat(parsers): update c3, desktop, dot, gomod, idl, julia, kitty, matlab, mlir, nu, php, php_only, tmux 2025-10-25 11:48:13 +02:00
zc he
9ee023538e
feat(nu): update syntax to Nu 0.108.0 (#8227)
also deduplicate bracket rules
2025-10-25 11:14:38 +02:00
Omar Valdez
400f38cc23
feat(hyprlang): update parser and queries (#8224) 2025-10-24 18:50:42 -07:00
Riley Bruins
f2204e58db
fix: use proper ; inherits syntax in queries (#8226)
Some queries don't add a colon after the `inherits` keyword, which nvim
could handle but `ts_query_ls` could not, causing it to give incomplete
diagnostics.
2025-10-24 18:47:39 -07:00
Isla Waters
4a9f57971a Remove empty capture based on ts_query_ls output 2025-10-24 09:31:21 +02:00
Isla Waters
eea5725822 feat(perl): Add language injection based on heredoc delimiter 2025-10-24 09:31:21 +02:00
Christian Clason
8fecb46258 feat(julia)!: switch to maintained fork
breaking change: ABI 15, drop support for emoji identifiers
2025-10-23 10:41:53 +02:00
zc he
30c466ad57
fix(nu): separate patterns for collection_type 2025-10-21 09:10:18 +02:00
Christian Clason
71bf1665f8 feat(parsers): update ada, cmake, desktop, dot, mlir, nu, qmljs, sparql, sql, superhtml, systemverilog, t32, tmux, xresources 2025-10-19 11:34:46 +02:00
Christian Clason
846d51137b
feat(julia): update builtin functions and types (#8203)
Update to Julia 1.12 (sync with upstream)
2025-10-17 13:54:28 +00:00
Christian Clason
cdb5d5ef23 docs(readme): remove wiki link 2025-10-17 14:24:49 +02:00
Riley Bruins
63fac0a576
fix(vue): @character.special highlights for :, . (#8200) 2025-10-15 23:17:41 -07:00
Christoph Sax
4968877bb2 fix(t32): update repo url
Switches the grammar repository from GitLab to GitHub.
2025-10-15 21:49:59 +02:00
Riley Bruins
0606c7a9dc feat(vue): delimiter highlight touch-ups 2025-10-12 11:22:15 +02:00
Riley Bruins
4b74045bbe chore: ask for file extension in new language PR template
This will really help me to search on github for diverse code samples.
2025-10-11 18:09:54 +02:00
Riley Bruins
09d50fd157 fix(kitty): align line continuation highlights
Changes them from `@comment` to `@punctuation.special`, which is how
they are in other languages.
2025-10-11 17:51:13 +02:00
Christian Clason
763f1e650b feat(parsers): update angular, comment, dart, desktop, enforce, erlang, gleam, gotmpl, hare, helm, javadoc, kitty, koto, mlir, racket, rust, scheme, superhtml, systemverilog, wit, xresources, yaml 2025-10-11 11:16:55 +02:00
Steven Xu
cbafde9925 feat(tmux)!: update parser and highlights
Breaking changes:

- Nodes `(variable_name)`, `(expr_variable_name)`, `(variable_name_short)`, are exposed as `(name)`.
2025-10-11 10:52:02 +02:00
Steven Xu
de003000a2 feat(tmux)!: update parser and highlights
Breaking changes:

- Node `(variable)` was renamed to `(expr_double_quotes)`.
- Node `(variable_raw)` was renamed to `(expr_single_quotes)`.
- Node `(string)` was renamed to `(str_double_quotes)`.
- Node `(raw_string)` was renamed to `(str_single_quotes)`.
- Node `(raw_string_quote)` was removed.
2025-10-10 12:53:39 +02:00
Yorick Peterse
3ab4f2d2d2 feat(inko): update parser for let pattern matching
Commit 9d7ed4 of the Inko tree-sitter grammar introduces support for
pattern matching in `let` expressions. This requires some corresponding
changes to the "local" queries to correctly define local variables. This
is done by simply defining locals for all "identifier_pattern" nodes,
instead of only doing this for "define_variable" nodes.
2025-10-07 10:00:15 +02:00
blindfs
0594d1ba65 feat(nu)!: update parser and queries 2025-10-06 16:31:28 +02:00
Christian Clason
01ced7499f feat(angular)!: update parser and queries
Breaking change: node `(static_member_expression)` was removed
2025-10-04 11:13:37 +02:00
Christian Clason
c579a8c0cf feat(parsers): update ada, c_sharp, css, dart, editorconfig, enforce, javadoc, koto, prisma, rust, sql, superhtml, t32 2025-10-04 11:07:11 +02:00
Christian Clason
b4888ed9e8 chore(gdscript): mark as unmaintained
Significant upstream breaking changes are not adapted to.
2025-10-04 10:58:16 +02:00
Yorick Peterse
b684696315 feat(inko): update parser and highlights
This commit includes syntax support for a few new syntax elements, and
updates the highlights queries to highlight two new expression keywords.
2025-10-03 15:18:41 +02:00
Omar Valdez
4709d4276c feat(python): highlight special brackets in format_expression 2025-10-03 09:53:33 +02:00
Riley Bruins
99bd52ba56
feat(java): highlight wildcards (#8165) 2025-10-02 03:33:49 +00:00
Riley Bruins
77362027f7
fix: remove redundant alternants (#8159) 2025-09-28 18:39:09 -07:00
Mouinul Hossain
db50897909
feat(parsers): add kitty (#8129) 2025-09-28 18:04:09 -07:00
Christian Clason
9176343647 feat(inko)!: update parser and queries
Breaking change: `(array_pattern)` rule and node was removed again.
2025-09-28 12:06:59 +02:00
Christian Clason
1df23c59d8 feat(parsers): update ada, cpp, desktop, erlang, godot_resource, ini, javadoc, mlir, powershell, rifleconf, slint, sql, superhtml, t32, xresources 2025-09-28 12:00:40 +02:00
Omar Valdez
5a70b1eb8c feat(hyprlang): highlight more exec keywords 2025-09-22 17:22:57 +02:00
Minijackson
53819acac2 feat(snl): add parser and queries 2025-09-22 15:41:39 +02:00
Riley Bruins
6ac9f2e512
fix: align line continuation highlights (#8146)
These should be `@punctuation.special`. Added the highlight for python,
cylc, and make. Corrected it for earthfile and matlab.
2025-09-21 16:59:47 -07:00
Christian Clason
bd99d6bd2b feat(koto)!: update parser and queries
Breaking changes: `call`, `index`, `lookup` fields removed
2025-09-21 10:42:51 +02:00
Christian Clason
a1d3efbdf5 feat(parsers): update ada, cuda, desktop, gdscript, json5, mlir, nu, slint, snakemake, supercollider, superhtml, vhdl, wgsl_bevy, xresources 2025-09-21 10:36:57 +02:00
Christian Clason
20fc6b1270 feat(python): revert breaking change
This reverts the update in
https://github.com/nvim-treesitter/nvim-treesitter/pull/8128 which
turned out to have further breaking consequences.

Pin the parser to the last release (tier 1) to avoid pulling in more
breaking changes.
2025-09-19 13:41:33 +02:00
Thibault de Villèle
c41b3b9841 feat(latex): add counter nodes' highlight rules 2025-09-19 10:35:18 +02:00
Thibault de Villèle
1b8622a830 feat(latex)!: update parser and queries
Breaking change: `(curly_group_label)` replaced by `(curly_group_text)`

see latex-lsp/tree-sitter-latex#213
2025-09-19 10:35:18 +02:00
sharpchen
317a77affc fix(c_sharp): missing highlight for parameter modifier 2025-09-19 10:27:32 +02:00
sharpchen
8ab64a37ea fix(c_sharp): missing query for delegate name 2025-09-17 21:05:25 +02:00
Christian Clason
1c760c1888 feat(parsers): update bash, c, cpp, desktop, djot, dtd, editorconfig, gdscript, go, html, idl, java, javadoc, javascript, json, markdown, markdown_inline, mlir, php, php_only, python, r, rust, scheme, ssh_config, supercollider, superhtml, systemverilog, templ, xml, xresources 2025-09-17 18:30:32 +02:00
Christian Clason
f4d22b96c5 docs(health): consistent use of tree-sitter-cli 2025-09-17 18:00:58 +02:00
Sergio A. Vargas
030e979b23
docs(README): clarify that tree-sitter-cli is required (#8124)
Seems like most distros have split out the CLI package under this name and reserve `tree-sitter` for the library (and crates) only.
2025-09-17 17:53:25 +02:00
purarue
7aa24acae3
feat(rifleconf): add parser and queries 2025-09-14 10:53:21 +02:00
Christian Clason
682d083292 feat(python)!: update parser and queries
Breaking change: anonymous node `"expect*"` was removed by the refactor.
2025-09-13 10:36:51 +02:00
Christian Clason
f6adaede57 feat(parsers): update authzed, bash, cpp, cylc, editorconfig, foam, gdscript, go, html, hurl, idl, java, javadoc, javascript, jsdoc, json, mlir, php, php_only, powershell, regex, rust, supercollider, zig 2025-09-13 10:27:44 +02:00
NullVoxPopuli
f42378a959
feat(glimmer_*): add glimmer_template folds (#8115) 2025-09-13 10:24:44 +02:00
altermo
7f8dd2e48b
fix(filetypes): correct glimmer_* mappings (#8110) 2025-09-10 07:29:48 +00:00
osthomas
fee71c102c
feat(snakemake): update queries (#8106)
also add indent tests
2025-09-07 13:58:28 +02:00
Christian Clason
939556333f feat(parsers): update arduino, desktop, hurl, mlir, query, slint, snakemake, xresources 2025-09-07 11:32:22 +02:00
Christian Clason
9addcdd015 feat(parsers): update agda, c3, embedded_template, javadoc, javascript, jinja, jinja_inline, pkl, slang, supercollider, sway, systemverilog 2025-09-06 11:12:58 +02:00
Riley Bruins
802195d8f1 feat(proto): folds for import statements 2025-08-31 08:06:48 +02:00
Riley Bruins
8fccdb3d49 feat(proto): more delimiter, property highlights 2025-08-31 08:06:48 +02:00
BlockLune
cd64fd3f44
feat(wxml): add parser and queries 2025-08-29 18:30:18 +02:00
Christian Clason
16da7ded58 feat(matlab)!: update parser and queries 2025-08-29 14:54:38 +02:00
Christian Clason
8302d4f547 feat(parsers): update bash, c, clojure, cpp, embedded_template, gap, go, html, java, javascript, json, json5, pkl, rust, supercollider 2025-08-29 14:49:35 +02:00
Christian Clason
85ec015f3b feat(nu)!: update parser and queries 2025-08-26 10:32:32 +02:00
Christian Clason
37cec5ec59 feat(gotmpl,helm)!: update parser and queries 2025-08-25 19:13:51 +02:00
Christian Clason
35a124cb60 feat(parsers): update arduino, blade, desktop, elixir, javadoc, llvm, mlir, perl, superhtml, vhdl, xresources, ziggy, ziggy_schema 2025-08-25 19:06:00 +02:00
Caleb White
9f15c2b050 fix(blade): fix highlighting of php tags 2025-08-25 15:39:40 +02:00
Yorick Peterse
44e90ec66e feat(inko): add support for array patterns
This updates the version of the Inko parser to the latest version and
includes indent support for the new array pattern node.
2025-08-21 19:51:10 +02:00
Christian Clason
6fd7117c1d feat(matlab)!: update parser and queries 2025-08-19 11:56:38 +02:00
Christian Clason
2f28a14ed2 feat(parsers): update arduino, chatito, desktop, editorconfig, gitattributes, gpg, idl, javadoc, mlir, pem, php, php_only, poe_filter, xresources 2025-08-19 11:51:52 +02:00
Christian Clason
32cb9f9b9d feat(parsers): update fennel, javadoc, llvm, matlab, mlir, nickel, nix, php, php_only, query, superhtml, vimdoc, wit 2025-08-16 10:11:22 +02:00
hsi
cabbd52bb8 fix(health): highlights legend label 2025-08-13 10:01:54 +02:00
Christian Clason
bf0234010a ci: bump actions/checkout to v5 2025-08-12 11:08:18 +02:00
Riley Bruins
4d43480167 ci: validate predicate/directive string parameters 2025-08-12 10:25:50 +02:00
Alexei Mozaidze
21da8ac251 fix(fennel): highlight $ in multi-symbol context properly
Highlights the dollar symbol properly in multi-symbol contexts like
`$.some.properties`
2025-08-12 10:25:22 +02:00
Caleb White
42ea539243 feat(php): update php and php_only parsers to v0.24.0 2025-08-12 10:25:14 +02:00
涵曦
13e3ce3bf4 feat(sproto): add parser 2025-08-12 10:24:58 +02:00
Christian Clason
9866036ec3 feat(parsers): update c3, c_sharp, desktop, editorconfig, fennel, gdshader, javadoc, llvm, matlab, nix, perl, scala, solidity, superhtml, xresource 2025-08-08 10:14:04 +02:00
Riley Bruins
4eb35c0344 feat(gdscript): misc operators, semicolon highlight 2025-08-06 18:49:54 +02:00
Christian Clason
37bcfdc6eb refactor(config): prefer vim.list.unique for normalization
Also fix some emmyluals warnings
2025-08-06 13:22:02 +02:00
Robert Muir
4d9916e477 fix(jinja_inline): fix crashing query pattern
If jinja_inline parser is regenerated, then this pattern hits an
"impossible" assert in tree-sitter query processing.
2025-08-05 20:06:49 +02:00
Robert Muir
a4fa3e2d18 Revert "fix(jinja): remove crashing pattern"
This reverts commit 8c8742871a.
2025-08-05 20:06:49 +02:00
Christian Clason
05f2910355 feat(systemverilog)!: update parser and queries
Breaking changes:
1. `(comment)` node split into `(one_line_comment)` and
   `(block_comment)`
2. named `(directive_foo)` nodes replaced by anonymous `"'foo"`
   (with backtick!) nodes -- but not consistently
2025-08-05 20:06:15 +02:00
Christian Clason
3561e1fb19 feat(parsers): update ada, fortran, idl, javadoc, matlab, nim, powershell, slang, superhtml, swift, templ 2025-08-02 14:53:13 +02:00
Christian Clason
b26b425829 feat(parsers): update gdscript, javadoc, lua, solidity, superhtml, systemverilog, zig, ziggy, ziggy_schema 2025-07-26 17:34:44 +02:00
Igor
12be0e9f24 fix(ini): register dosini and confini filetypes 2025-07-26 17:32:28 +02:00
MeanderingProgrammer
57aa15d4cc fix(install): skip duplicate dependencies 2025-07-25 11:55:13 +02:00
Christian Clason
5d539943c6 feat(parsers): update angular, beancount, fennel, gleam, idl, javadoc, jinja, jinja_inline, koto, llvm, swift, systemverilog, tera, vhdl 2025-07-23 13:38:53 +02:00
Riley Bruins
40cca05b40 fix(c, ecma): remove invalid predicate parameters
These are not valid named nodes in their respective languages.
2025-07-22 09:52:32 +02:00
Christian Clason
8c8742871a fix(jinja): remove crashing pattern
https://github.com/cathaysia/tree-sitter-jinja/issues/37
2025-07-21 11:21:52 +02:00
NullVoxPopuli
6b3bf164b2
feat(glimmer): add fold queries (#8020) 2025-07-21 09:40:37 +02:00
MeanderingProgrammer
3650b4ef6a refactor(install): replace status enum with boolean 2025-07-21 09:40:08 +02:00
MeanderingProgrammer
d116118add fix(install): don't make "installed" status persistent
Problem: Setting `install_status` to "installed" skips any future
install or update operation (even if forced). In particular, this breaks
`:TSUpdate` when calling `install()` in config files.

Solution: Don't set "installed" when skipping install and clear status
on successful operations.
2025-07-20 14:39:10 +02:00
Christian Clason
f14b356d54 feat(chatito)!: update parser and queries
node `(eq)` is replaced by field `eq: _`
2025-07-20 11:53:37 +02:00
Jonas Chevalier
afe267b50e
chore(nix): update url and maintainers 2025-07-20 09:50:56 +00:00
Christian Clason
d6bce02b89 feat(parsers): update beancount, brightscript, enforce, gdscript, gpg, groq, matlab, mlir, nix, pem, pymanifest, t32, udev, vhdl 2025-07-20 11:43:07 +02:00
Robert Muir
20d77c2e5b fix(jinja): assign highlights to all variables and functions
The majority of jinja variables aren't assigned any highlights at all.
Assign @variable to all identifiers.

Jinja filters without parameters are not highlighted as functions: add a
query for these.

Refine the existing @variable.member to only capture identifiers instead
of broader nodes.
2025-07-19 18:25:47 +02:00
Christian Clason
1e3b7562c2 feat(wit)!: update parser and queries 2025-07-19 15:19:50 +02:00
Christian Clason
a98e67ad40 fix(wit): update repo url 2025-07-19 15:06:34 +02:00
Riley Bruins
fba060b623
feat(pkl): add parser and queries (#8011) 2025-07-19 11:36:38 +02:00
Alan Russell
61ec748ef7
feat(groq): add parser and queries (#8008) 2025-07-18 18:04:42 +02:00
Christian Clason
a5edb0a274 feat(parsers): update arduino, editorconfig, gdscript, idl, javadoc, koto, matlab, mlir, nix, nu, powershell, printf, properties, slint, superhtml, systemverilog, t32, tera, twig, xcompose, xresources, ziggy, ziggy_schema 2025-07-17 11:42:27 +02:00
Riley Bruins
992e9ef3d0 ci: ensure parsers have a supported ABI version 2025-07-16 10:54:41 +02:00
Riley Bruins
8d8ca0996c docs: specify fold dos and don'ts 2025-07-15 10:53:32 +02:00
Riley Bruins
96f51adf71
fix(c_sharp): "<", ">" in type param lists are brackets (#8003) 2025-07-15 00:55:29 +00:00
Riley Bruins
6c2234f7ba
feat(c_sharp): highlight :: (#8002) 2025-07-14 17:48:23 -07:00
Christian Clason
c3ecec599b feat(parsers): update beancount, blade, cpp, desktop, gosum, javadoc, liquidsoap, mlir, nix, slint, systemverilog, t32, vim, xresources 2025-07-13 11:35:38 +02:00
Caleb White
c9e4edc127 feat(blade): update blade parser and queries 2025-07-11 17:34:30 +02:00
Christian Clason
4eb12d7a1f feat(ziggy,ziggy-schema): update parser and queries
Breaking change: ziggy-schema removed "map" node
2025-07-09 10:30:54 +02:00
Christian Clason
3dc6834b30 feat(parsers): update blueprint, desktop, fortran, javadoc, llvm, mlir, nu, requirements, superhtml, swift, v, xresources 2025-07-08 16:58:37 +02:00
Christian Clason
4400990e73 feat(vim): highlight "trim" in script heredocs
Allow the optional "trim", as documented in ":help :lua-heredoc".
2025-07-07 12:22:10 +02:00
Christian Clason
0d32ec3c3e feat(latex)!: update parser and queries
Breaking change: `label_definition`, `label_text` patterns
2025-07-05 17:46:07 +02:00
Christian Clason
80281c19fd feat(parsers): update c3, cpp, d, faust, fsharp, javadoc, julia, liquidsoap, meson, mlir, nu, powershell, roc, swift, systemverilog, t32, v 2025-07-05 17:46:07 +02:00
Igor
dafb3cb3cb fix(http): prefer folding requests 2025-07-04 08:56:45 +02:00
Riley Bruins
04935dec42 fix: remove import references to jsx/locals.scm
There are no JSX locals (yet...?)
2025-07-03 18:33:31 +02:00
Baruch Even
1f069f1bc6
feat(D): highlight (string) etc. as @keyword.type (#7978)
Co-authored-by: Baruch Even <baruch@weka.io>
2025-06-29 16:10:29 +00:00
przepompownia
dbb63c8b7a feat(php): fold match_expression 2025-06-29 15:59:54 +02:00
przepompownia
4b2e9b049c feat(php): fold array_creation_expression 2025-06-29 15:17:01 +02:00
Christian Clason
5948977de4 feat(parsers): update angular, clojure, gleam, idl, javadoc, jinja, jinja_inline, liquidsoap, nim, nu, poe_filter, r, ssh_config, systemverilog, v 2025-06-29 11:39:30 +02:00
Christian Clason
2e8f8562e6 fix(scripts): sort list of updated parsers 2025-06-29 11:39:30 +02:00
Eric Mrak
7110df63e1
feat(fish): more builtin commands and variables (#7972)
builtin commands:
* abbr
* path

builtin variables:
* fish_cursor_*
2025-06-26 09:04:48 +02:00
Christian Clason
77ba555cef ci: bump luals to 3.15.0 2025-06-25 12:01:18 +02:00
Christian Clason
98459ffcf7 fix(health): sort language names 2025-06-24 12:23:23 +02:00
Christian Clason
1181cd9a25 feat(verilog)!: rename to systemverilog
Grammar name was changed to coincide with repository name
2025-06-24 10:07:36 +02:00
Christian Clason
13ddd4d752 feat(swift)!: update parser and queries 2025-06-24 10:07:24 +02:00
Christian Clason
6c50310371 chore(wit): mark as unmaintained 2025-06-23 20:25:00 +02:00
Luis Calle
2317241896
fix: register powershell language for ps1 filetype (#7965)
* chore: sort languages

* fix: register `powershell` language for `ps1` filetype
2025-06-23 18:15:08 +00:00
Christian Clason
8867a9d6bf feat(powershell)!: update parser and queries
removed nodes: `"class"`, `"enum"`
2025-06-22 15:51:32 +02:00
Christian Clason
1bfa557b7d feat(parsers): update gleam, latex, typespec, purescript, heex, nu 2025-06-22 15:46:42 +02:00
guilhas07
2a677dede2 feat(vue): add template commentstring metadata 2025-06-18 18:34:40 +02:00
Christian Clason
7e6fbcaa20 feat(purescript)!: update parser and queries
removed note: `(constructor_operator)`
2025-06-17 15:55:21 +02:00
Christian Clason
9807487fe9 feat(parsers): update desktop, query, editorconfig, xresources, hcl, slint, markdown_inline, matlab, terraform, templ, nu, vhdl, tera, markdown, javadoc 2025-06-17 15:55:21 +02:00
Christian Clason
43b7f16c50 feat(parsers): update php_only, javadoc, erlang, faust, php, roc, slim, fortran, terraform, fish, mlir, sourcepawn, latex, matlab, hcl, vhdl 2025-06-15 10:52:24 +02:00
uncenter
a64ef334be
fix(css): universal selector "*" has precedence over operator (#7948) 2025-06-14 11:01:04 +02:00
Igor
c29969e8ef feat(dot): fold queries 2025-06-13 09:24:28 +02:00
Christian Clason
0fb1c6e92e feat(parsers): update bash, purescript, r, cylc, meson, mlir, xresources, markdown, markdown_inline, scala, javadoc, slint, desktop, enforce, editorconfig, query 2025-06-09 17:47:41 +02:00
Éric NICOLAS
9c03c835fb fix(bash): highlight shebang also when spaced
This commit aligns the shebang highlighting in bash syntax to what the
Linux kernel will recognise as a valid shebang construct.

In summary, the kernel will accept both headers:

    #!/usr/bin/env lua
    #! /usr/bin/env lua

The second one is quite prominently used throughout documentation
online, such as on Wikipedia's page for Shebang (Unix) [1].

Some sources are adamant it wouldn't be supported at a kernel level, but
it looks to me, upon closer inspection of the current kernel code [2],
that it is indeed quite evidently valid.  It'll simply skip over to the
first character that's neither a space 0x20 nor a tab 0x09.

[1] https://en.wikipedia.org/wiki/Shebang_(Unix)
[2] ec7714e494/fs/binfmt_script.c (L44-L71)
2025-06-09 10:43:31 +02:00
Jaehwang Jung
c48b37a3c9 feat(cpp): highlight template method call 2025-06-07 10:28:49 +02:00
Christian Clason
faf63903ff fix(ipkg)!: remove parser and queries
grammar repo is 404 (user removed) and no forks exist
2025-06-06 16:59:44 +02:00
Omar Valdez
27d0bef81e feat(desktop): update parser and queries 2025-06-06 09:07:06 +02:00
Christian Clason
f976acdc9c refactor(install): inline, rename, annotate 2025-06-04 11:35:41 +02:00
Christian Clason
057e845518 feat(install): support custom queries 2025-06-04 11:35:41 +02:00
Christian Clason
fb9b2cfdc3 feat(parsers): update bash, scala, slang, hyprlang, ini, query, javadoc, xml, php_only, angular, dtd, nu, php 2025-06-04 10:37:27 +02:00
Christian Clason
27b0bd487c feat(nickel)!: update parser and queries
Breaking change: `(record_field)` -> `field_decl`
2025-06-02 13:30:07 +02:00
Christian Clason
6d54a47f44 feat(parsers): update desktop, javadoc, t32, templ, fortran, editorconfig, mlir, xresources, ocaml_interface, r, ocaml 2025-06-02 13:30:07 +02:00
Christian Clason
3cad4eb434 fix(lua): fix some emmyluals warnings 2025-05-31 11:30:56 +02:00
Éric NICOLAS
9a51f860c1 fix(git_config): match lowercase Git config vars
Git config's sections, variable names, and (sometimes) subsections are
case-insensitive.  This commit proposes to match the full lowercase
variants in addition to the non-normalised, lowerCamelCase ones.

See `git help config`
2025-05-31 10:12:23 +02:00
Christian Clason
01dd4b05cf fix(check-queries): only show timings for existing queries 2025-05-30 16:23:44 +02:00
Christian Clason
fa0bb30ebd feat(parsers): update gdscript, gitattributes, godot_resource, xresources, yaml, ocaml, koto, ocaml_interface, c, ini, mlir, scheme, slint, c3, r, clojure, desktop, editorconfig, fortran 2025-05-30 10:25:47 +02:00
Christian Clason
ff770d718b fix(install): don't print operation summary by default
Problem: People complain about noisy `install()`.

Solution: Gate operation summary behind `summary` install option
(default false, set to true for interactive `:TS*` commands).
2025-05-29 20:08:10 +02:00
Christian Clason
ce903fde5d feat(api): expose list of available and installed languages 2025-05-29 12:11:56 +02:00
Christian Clason
0860b9b107 fix(config): check both installed parsers and queries
Problem: Can't uninstall custom parsers without queries since
`installed_parsers` only iterates over installed queries (to include
query-only languages, and to avoid string manipulation).

Solution: Iterate over both queries and parsers to collect list of
installed languages (optionally only queries or only parsers).
2025-05-29 11:52:58 +02:00
Christian Clason
03c9048090 fix(install): only install queries for bundled parsers 2025-05-29 11:52:58 +02:00
Christian Clason
f9ab837ca1 fix(install): don't skip un-tiered parsers 2025-05-29 11:52:58 +02:00
Christian Buttner
c59004f1e0
feat: add c3 (#7891) 2025-05-28 23:04:10 +02:00
Noah Bogart
71d2fd1bd4
fix(just): do not restrict @function.call to explicit list (#7905) 2025-05-28 22:44:34 +02:00
Christian Clason
024e6c5e46 fix(queries): fix rebase errors on main 2025-05-28 14:35:36 +02:00
Christian Clason
0140c29b31 fix(health): only require ts>=v0.25 2025-05-27 15:25:49 +02:00
Marc Jakobi
dd63d7141f fix(haskell): properly set inline-python injection language 2025-05-27 14:17:05 +02:00
Christian Clason
61b0a05ec0 fix(install): create cache dir if not existing 2025-05-26 17:21:18 +02:00
Christian Clason
1043871ef4 fix(swift): mark as unmaintained
Prevent from updating parser with breaking changes until queries are
adapted.
2025-05-26 14:57:57 +02:00
Christian Clason
c1dfc39285 fix(config): prepend install_dir to rtp 2025-05-25 13:11:28 +02:00
Christian Clason
0d60a09252 fix(typst): restore missing injections 2025-05-25 10:51:44 +02:00
Christian Clason
354c30d2a2 feat(parsers): update desktop, dtd, editorconfig, janet_simple, liquid, c, v, perl, mlir, templ, vhdl, xml, xresources, yaml, tlaplus, cmake 2025-05-24 19:27:04 +02:00
Omar Valdez
652831b231 feat(bash): highlight variable argument for printf -v 2025-05-24 11:39:59 +02:00
Christian Clason
c78594ce06 ci(test): throttle all install steps 2025-05-22 19:50:31 +02:00
Christian Clason
011f02936f fix(install): return task object in API functions 2025-05-22 08:34:45 +02:00
Yorick Peterse
d08cf75e1b feat(inko): add scoping to the locals queries
This way tooling that makes use of these queries (e.g. snacks.nvim) is
aware of the scoping of Inko types and methods.
2025-05-22 07:47:03 +02:00
Christian Clason
b19b5ce171 docs: final update after rewrite
Make clear this is not the default branch
2025-05-21 09:15:29 +02:00
Christian Clason
40cbddedf7 feat(parsers): update markdown_inline, markdown, vimdoc, fsharp, pascal, racket, lua, scheme, gleam, ocamllex, query 2025-05-18 10:22:42 +02:00
Riley Bruins
168fe16cdd fix: tidy up some query mistakes
Revealed by the capture-less patterns lint
2025-05-18 09:46:27 +02:00
Christian Clason
a663e69447 feat(parsers): update javadoc, jq, hcl, query, smithy, earthfile, tcl, llvm, godot_resource, git_config, terraform, teal, gdscript, mlir 2025-05-16 18:33:52 +02:00
Lewis Russell
69371f0148 feat(install)!: migrate to latest async.nvim impl (#7856)
Provides significantly simpler blocking installation and update.
2025-05-16 18:33:52 +02:00
Christian Clason
7a4a35de3e refactor(indent): use `node:byte_length() 2025-05-16 15:00:37 +02:00
Christian Clason
b0a20057b0 feat(config)!: remove ignore_install
This was only useful for no longer supported `auto_install` option.
2025-05-16 08:48:27 +02:00
Christian Clason
864e75a85d fix(c,cpp,fsharp,idl,powershell,sql,systemtap): remove unneeded escapes 2025-05-13 18:12:58 +02:00
Christian Clason
25f08b82af fix(hcl): remove unnecessary escapes 2025-05-13 18:12:58 +02:00
Christian Clason
6b55bc0fab ci(test): remove parser cache
Since installation now installs parsers _and_ queries, caching parsers
doesn't allow skipping the installation step (and caching queries does
not pay off).
2025-05-13 18:12:58 +02:00
Christian Clason
e8bfe271b0 docs: update to rewrite
This updates

* README
* CONTRIBUTING
* the `:h nvim-treesitter` documentation

to the current state of `main`. It also adds a pull request template for
adding a new language.
2025-05-12 18:43:41 +02:00
Christian Clason
a7ab4381ae feat(parsers): update t32, query, markdown, markdown_inline, meson, hyprlang, mlir, cpp, cylc 2025-05-12 18:43:41 +02:00
Christian Clason
f10bcac66b feat(parsers): update vim, gren, comment, purescript, elm, matlab, javadoc, swift, godot_resource, query, vimdoc, ledger 2025-05-12 18:43:41 +02:00
Christian Clason
dc8f3415a7 feat!: update tier 1 parsers to versions 2025-05-12 18:43:41 +02:00
Christian Clason
18bb653917 feat(locals)!: remove locals module
Problem: `locals.lua` was neither used nor tested, and providing it goes
against the goal of nvim-treesitter not being a required dependency for
other plugins.

Solution: Remove the module and document that the queries are provided
as-is for limited backward compatibility only.
2025-05-12 18:43:41 +02:00
Christian Clason
53dccb3a77 feat(tests)!: new infrastructure based on makefile
Problem: Not easy to run all checks and tests locally. Redundant CI
workflows.

Solution: Separate CI into two workflows:
 * lint: Lua files (stylua, luals), query files (valid captures,
   predicates, directives using tsqueryls), docs
   (SUPPORTED_LANGUAGES.md) -- does not need parser installation
 * tests: parsers (ABI compatibility), query files (tsqueryls on
   Linux/macOS; nvim on Windows), highlight and indent tests (separated
   for better readability) -- needs parser installation (but only once)

Switch to https://github.com/nvim-treesitter/highlight-assertions fork
with ABI 15 support.

Run all tests (on Linux and macOS) through `make` (`formatlua`,
`checklua`, `lintquery`, `formatquery`, `checkquery`, `docs`, `tests`),
which downloads and caches all necessary dependencies.

Remove `update-readme` workflow (replaced by lint job on PRs).
2025-05-12 18:43:41 +02:00
Riley Bruins
4e906caca3 refactor(locals): fix type annotations and warnings 2025-05-12 18:43:40 +02:00
Christian Clason
afaf01ebd3 tests(angular): don' reset filetype
`htmlangular` filetype support is now included in Nvim, so don't set
the filetype.
2025-05-12 18:43:40 +02:00
Christian Clason
75ee7ff2f0 tests(gleam): fix assert tests that no longer parse correctly 2025-05-12 18:43:40 +02:00
Christian Clason
a83f2d1417 feat(vim): update parser and queries
* add support for `:substitute` command
* add support for `=` lua chunks
2025-05-12 18:43:40 +02:00
Christian Clason
3d0e642764 feat(gdscript)!: update parser and queries
`(underscore)` node was removed
2025-05-12 18:43:40 +02:00
Christian Clason
f7c5f7de55 feat(parsers): update robot, earthfile, racket, javadoc, scheme, t32, tact, templ, kotlin, tcl, meson, mlir 2025-05-12 18:43:40 +02:00
Christian Clason
11736494df fix(indent): don't skip parsing for yaml 2025-05-12 18:43:40 +02:00
Christian Clason
44bb06bc12 chore: remove lockfile and update script
`main` branch and `parsers.lua` is the record of truth now
2025-05-12 18:43:40 +02:00
Christian Clason
53d7118483 refactor(lua): fix some luals warnings 2025-05-12 18:43:40 +02:00
Christian Clason
bdc2e01958 feat(install)!: always generate from json if possible 2025-05-12 18:43:40 +02:00
Christian Clason
522e0c6991 feat(setup)!: remove ensure_install field
Instead, call `require('nvim-treesitter').install( { ... } )` manually.

This gives users full control over how they want to install parsers
(sync, from grammar, limited concurrency) and obviates the need for
calling `setup` for most users.
2025-05-12 18:43:40 +02:00
Christian Clason
73adbe597e feat(parsers): update swift, tact, tcl, templ, mlir, kotlin, koto, elixir, php_only, ocaml, ocaml_interface, php, astro, slang, slim, blade, gleam, v, ledger 2025-05-12 18:43:40 +02:00
Christian Clason
037ac775e1 feat: add .tsqueryrc.json 2025-05-12 18:43:40 +02:00
Christian Clason
ed1f573aae feat(parsers): update ziggy, ziggy_schema, bibtex, latex 2025-05-12 18:43:40 +02:00
Christian Clason
308c9b26c7 feat(tcl)!: update parser and queries 2025-05-12 18:43:40 +02:00
Christian Clason
990110336c feat(julia)!: update parser and queries 2025-05-12 18:43:40 +02:00
Christian Clason
c13511c884 feat(parsers): update nickel, sql, devicetree, dhall, htmldjango, t32, gap, javadoc, templ, jinja, tera, verilog, meson, mlir, typespec, wit, phpdoc, superhtml, git_config, swift, terraform, vim, koto, rasi, rescript, bp, enforce, erlang, jinja_inline, cmake, fennel, comment, slint, elm, rust, hcl 2025-05-12 18:43:40 +02:00
Christian Clason
cbfe8a20c7 feat(html): use gsub for mimetype lookup 2025-05-12 18:43:40 +02:00
Christian Clason
328ee3db54 fix(install): skip tier 4 parsers when installing and updating 2025-05-12 18:43:40 +02:00
Christian Clason
9365cf8a97 fix(install): don't prompt on installed parsers (skip)
Use `:TSInstall!` or `force = true` to reinstall.
2025-05-12 18:43:40 +02:00
Christian Clason
12e0246e4f fix(formatter): increase match limit
Problem: Some very long patterns were not formatted correctly.

Solution: Increase the match limit when iterating to 1024.
2025-05-12 18:43:40 +02:00
przepompownia
6fe0032640 feat(install): allow pass callback to update()
Problem: cannot run `:TSUpdate synchronously`

Solution: pass callback used after exiting jobs
(like in `install-parsers`).
2025-05-12 18:43:40 +02:00
Sebastian Lyng Johansen
02a1a0537c fix(install): early return if parser_info does not exist 2025-05-12 18:43:40 +02:00
Christian Clason
a9f34d5a76 feat(parsers): rework tiers
* stable: updates follow semver releases (todo)
* unstable: updates follow HEAD (default)
* unmaintained: no automatic updates
* unsupported: no updates, cannot be installed
2025-05-12 18:43:40 +02:00
Christian Clason
188bbf7a09 fix(ci): update to changed neovim release name 2025-05-12 18:43:40 +02:00
Christian Clason
aaf5b7fdf7 fix(install): return error code in callback 2025-05-12 18:43:40 +02:00
Christian Clason
a2841d29d7 feat(install)!: bump minimum tree-sitter version to 0.24 2025-05-12 18:43:40 +02:00
Christian Clason
c5a8c9d01a ci(tests): add optional workflow for generating grammars
run on PR by adding label `ci:generate` or manually
2025-05-12 18:43:40 +02:00
Christian Clason
83dae49a10 feat(install): allow specifying max jobs 2025-05-12 18:43:40 +02:00
Christian Clason
ab230eadd4 feat(config)!: remove auto_install
use https://github.com/lewis6991/ts-install.nvim instead
2025-05-12 18:43:40 +02:00
Christian Clason
a8677385b7 feat(install)!: drop support for git
Problem: Using git for installing parsers can lead to data loss if in a
git commit buffer.

Solution: Only support downloading via curl+tar, which are installed on
all supported platforms (since Windows 10). Curl will also be required
for WASM parsers (and for `vim.net.download()`).
2025-05-12 18:43:40 +02:00
Christian Clason
214cfcf851 feat!: use tree-sitter build 2025-05-12 18:43:40 +02:00
Christian Clason
c17de56890 feat!: track parser revision in Lua
Problem: Tracking parser revision in lockfile and allowing override
through the parsers module complicates the code. In addition, only
revision changes are handled robustly, not changes to other installation
info.

Solution: Track parser revision in the parsers module directly. Reload
parser table on every install or update call. Support modifying parser
table in a `User TSUpdate` autocommand.
2025-05-12 18:43:40 +02:00
Christian Clason
054080bf59 fix: vim.tbl_flatten is deprecated 2025-05-12 18:43:40 +02:00
Christian Clason
5a38df5627 feat(install)!: generate from json instead of requiring node
Problem: Many parsers require node/npm to evaluate the `grammar.js`
before being able to generate a parser from it.

Solution: Generate from `grammar.json` instead, which is fully resolved.
Drops `node` and `npm` as (optional) requirements for nvim-treesitter.

Note that this requires parsers to commit the generated json iff the
grammar requires evaluation (which is currently the case for all tracked
languages).
2025-05-12 18:43:40 +02:00
nvim-treesitter-bot[bot]
8f8cf7144d bot(readme): update 2025-05-12 18:43:40 +02:00
Christian Clason
c70daa36dc feat(install)!: add explicit path field to parser info (#6476)
Problem: Using `url` for both remote repo and local path complicates the
code.

Solution: Add `path` field that overrides `url` and bypasses
git-specific manipulations, i.e., the contents of the `path` are used
as-is (no git repo needed).

This means `:TSUpdate` will skip such parsers; use `:TSInstall!` instead
after making local changes.

---------

Co-authored-by: Lewis Russell <lewis6991@gmail.com>
2025-05-12 18:43:40 +02:00
Lewis Russell
0bb981c876 fix: do not use vim.iter (#6469) 2025-05-12 18:43:40 +02:00
Lewis Russell
421e2fb7b2 feat: improve logging of failed installs 2025-05-12 18:43:40 +02:00
Christian Clason
a8f5641ab3 feat(install)!: remove support for C++ scanners 2025-05-12 18:43:40 +02:00
Phạm Huy Hoàng
429e6f446b doc: better clarification of highlights/injections 2025-05-12 18:43:40 +02:00
Phạm Huy Hoàng
039fe9095d fix(format): update scripts to support nightly (#6126)
No need for assert as the use is contained within the script only
2025-05-12 18:43:40 +02:00
Gregory Anders
be5f9b0eaa fix: update add_predicate and add_directive calls for upstream (#6106)
Update custom predicates and directives to handle multiple nodes per
capture ID per changes upstream.
2025-05-12 18:43:40 +02:00
Christian Clason
885c2960ef fix: better output for update-lockfile 2025-05-12 18:43:40 +02:00
Christian Clason
e77506bde3 feat: improve check-queries 2025-05-12 18:43:40 +02:00
Christian Clason
178c6a84c1 docs: update CONTRIBUTING.md 2025-05-12 18:43:40 +02:00
Lewis Russell
5f2c6c0c83 refactor: pull out predicate function 2025-05-12 18:43:40 +02:00
Lewis Russell
59f5d64a61 fix: update vim.system types 2025-05-12 18:43:40 +02:00
Lewis Russell
efbc2a4b72 fix: remove downcase! directive use 2025-05-12 18:43:40 +02:00
Lewis Russell
1bec16362f feat: allow a custom revision in install_info 2025-05-12 18:43:40 +02:00
Pham Huy Hoang
3966b8808b fix!: indents now rely on treesitter highlight
- Apply suggestions from Lewis to only parse visible lines
- Fix failed tests
2025-05-12 18:43:40 +02:00
Christian Clason
abcbe65b6e docs(readme): document 'location' key 2025-05-12 18:43:40 +02:00
Pham Huy Hoang
673fdccd21 tests: remove set ft 2025-05-12 18:43:40 +02:00
Lewis Russell
b5a3f5c286 fix: cleanup diagnostics 2025-05-12 18:43:40 +02:00
Lewis Russell
26302f412f fix: add stricter cc options (#5063) 2025-05-12 18:43:40 +02:00
Christian Clason
f13420ccff fix: remove upstreamed directives
`#inject-lang!` and `#trim!`; fix `set-lang-from-mimetype`
2025-05-12 18:43:40 +02:00
TheLeoP
dd6ec13268 fix: always normalize paths
Not doing this results in paths with a mix of '\\' and '/' for Windows.
This isn't a problem when dealing with Neovim/luv APIs, but it is a
problem when comparing strings.
2025-05-12 18:43:40 +02:00
TheLeoP
b4c9c81a80 fix: check if config has install_info in filter 2025-05-12 18:43:40 +02:00
Lewis Russell
934b751f9d fix: check queries in needs_update() 2025-05-12 18:43:40 +02:00
Lewis Russell
041f117fb1 fix: filter languages through parser.configs 2025-05-12 18:43:40 +02:00
Christian Clason
bae77b87b1 feat: add parser tiers
Tier 1: Stable
Tier 2: Core (maintained by org members)
Tier 3: Community (maintained by external contributors, to varying
degree)
Tier 4: Unsupported (lacking active maintainer or declared
experimental); skipped in lockfile update and ignored for automatic
install by default
2025-05-12 18:43:40 +02:00
Christian Clason
f0a984347c feat!: drop makefile support, norg parser
Norg install_info and queries are maintained by neorg.

All other parsers are compatible with C++11, so fix that as standard.
(Can be bumped if all supported platforms support C++14.)

Remove Makefile support, as it's no longer needed.
2025-05-12 18:43:40 +02:00
Lewis Russell
c5152f3e83 refactor: use vim.system (#4923) 2025-05-12 18:43:40 +02:00
Christian Clason
68508631de fix: expand tiers in ignore_install 2025-05-12 18:43:40 +02:00
Christian Clason
5a70048116 feat: drop TSInstallInfo in favor of better checkhealth
also fixes the hole in install.compilers
2025-05-12 18:43:40 +02:00
Christian Clason
37957d6bcf refactor: use vim.uv 2025-05-12 18:43:40 +02:00
Christian Clason
cd2c826972 fix: install dependencies 2025-05-12 18:43:40 +02:00
Christian Clason
9c0a99819c ci: remove update-lockfile shell script 2025-05-12 18:43:40 +02:00
Lewis Russell
cde679e435 refactor: rewrite installation using jobs and async
Replace sync variants with callback support
2025-05-12 18:43:40 +02:00
Christian Clason
5aa2984a02 refactor: use vim.fs.joinpath 2025-05-12 18:43:40 +02:00
Christian Clason
eb1b6ec542 feat!: drop luarocks release 2025-05-12 18:43:40 +02:00
Christian Clason
5817ff01b5 feat(locals)!: refactor locals.lua into standalone
Co-authored-by: TheLeoP <eugenio2305@hotmail.com>
2025-05-12 18:43:40 +02:00
Christian Clason
692b051b09 feat!: drop modules, general refactor and cleanup 2025-05-12 18:43:40 +02:00
ObserverOfTime
310f0925ec feat(c-family): inherit injections 2025-05-12 18:43:40 +02:00
Marc Jakobi
628d5e442c injections(nix): add nixosTest.testScript + home-manager nvim config
(+ add Check to mkDerivation bash matches)

(+ add Check to mkDerivation bash matches)
2025-05-12 18:43:40 +02:00
ObserverOfTime
b171f948da feat(yuck): add missing injections
And builtin variable highlights
2025-05-12 18:43:40 +02:00
1377 changed files with 14804 additions and 14207 deletions

31
.emmyrc.json Normal file
View file

@ -0,0 +1,31 @@
{
"$schema": "https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json",
"format": {
"externalTool": {
"program": "stylua",
"args": [
"-",
"--stdin-filepath",
"${file}"
]
}
},
"diagnostics": {
"disable": [
"unnecessary-if",
"incomplete-signature-doc"
],
"enables": [
"iter-variable-reassign",
"non-literal-expressions-in-assert",
"missing-global-doc"
]
},
"codeAction": {
"insertSpace": true
},
"strict": {
"typeCall": true,
"arrayIndex": true
}
}

4
.gitattributes vendored Normal file
View file

@ -0,0 +1,4 @@
runtime/queries/**/*.scm linguist-language=tsq
doc/*.txt linguist-documentation
SUPPORTED_LANGUAGES.md linguist-generated
lua/nvim-treesitter/async.lua linguist-vendored

2
.github/FUNDING.yml vendored
View file

@ -1,2 +0,0 @@
open_collective: "nvim-treesitter"
github: "nvim-treesitter"

View file

@ -0,0 +1,47 @@
<!--
Before proceeding, make sure you have read https://github.com/nvim-treesitter/nvim-treesitter/blob/main/CONTRIBUTING.md!
Make sure to fill out all fields and read the checklist at the end.
-->
# Name of language
<!-- Link to an official description of the language -->
https://...
Language file extension, if applicable: (e.g. `.zu`)
<details>
<summary>Representative code sample</summary>
```
max. 50 lines
```
</details>
## Parser repo
https://github.com/...
<details>
<summary>Parsed tree for code sample</summary>
```
paste output of tree-sitter parse or :InspectTree here
```
</details>
## Queries
Source of queries: https://github.com/... (or "written from scratch")
<details>
<summary>Screenshots of code sample</summary>
<!-- paste screenshot of code sample using provided queries here -->
</details>
<!--
CHECKLIST: _Before_ submitting, make sure
* `./scripts/install-parsers.lua <language>` works without warnings
* `./scripts/install-parsers.lua --generate <language>` works without warnings
* `make query` works without warning
* `make docs` is run
-->

16
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,16 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 3
commit-message:
prefix: "ci"
labels:
- "CI"
groups:
actions:
patterns: ["*"]

5
.github/pull_request_template.md vendored Normal file
View file

@ -0,0 +1,5 @@
<!--
Before proceeding, make sure you have read https://github.com/nvim-treesitter/nvim-treesitter/blob/main/CONTRIBUTING.md!
If you are adding a new parser, use this link instead:
<https://github.com/nvim-treesitter/nvim-treesitter/compare/main...my-branch?quick_pull=1&template=new_language.md>
-->

62
.github/workflows/downstream.yml vendored Normal file
View file

@ -0,0 +1,62 @@
name: Tests
on:
pull_request:
branches:
- "main"
paths:
- "lua/nvim-treesitter/parsers.lua"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
test-downstream:
name: Check downstream queries
runs-on: ubuntu-latest
env:
NVIM: "nvim"
steps:
- uses: actions/checkout@v6
- uses: tree-sitter/setup-action/cli@v2
- name: Install and prepare Neovim
env:
NVIM_TAG: "nightly"
run: |
bash ./scripts/ci-install.sh
- name: Compile parsers
run: $NVIM -l ./scripts/install-parsers.lua --max-jobs=10
- name: Set up ts_query_ls
run: curl -fL https://github.com/ribru17/ts_query_ls/releases/latest/download/ts_query_ls-x86_64-unknown-linux-gnu.tar.gz | tar -xz
- name: Clone textobjects
uses: actions/checkout@v6
with:
repository: nvim-treesitter/nvim-treesitter-textobjects
ref: main
path: .tests/nvim-treesitter-textobjects
sparse-checkout: queries
- name: Check textobjects
working-directory: .tests/nvim-treesitter-textobjects/
run: ../../ts_query_ls check queries/
- name: Clone context
if: always()
uses: actions/checkout@v6
with:
repository: nvim-treesitter/nvim-treesitter-context
ref: master
path: .tests/nvim-treesitter-context
sparse-checkout: queries
- name: Check context
if: always()
working-directory: .tests/nvim-treesitter-context/
run: ../../ts_query_ls check queries/

View file

@ -1,51 +1,50 @@
name: Linting and style checking
name: Lint
on:
push:
branches:
- "main"
pull_request:
branches:
- "master"
- "main"
workflow_dispatch:
jobs:
luacheck:
name: Luacheck
runs-on: ubuntu-latest
lua:
name: Lint Lua files
runs-on: ubuntu-slim
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Prepare
- name: Format
run: |
sudo apt-get update
sudo apt-get install luarocks -y
sudo luarocks install luacheck
- name: Run Luacheck
run: luacheck .
stylua:
name: StyLua
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint with stylua
uses: JohnnyMorganz/stylua-action@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
version: latest
args: --check .
format-queries:
name: Lint queries
runs-on: ubuntu-latest
env:
NVIM_TAG: stable
steps:
- uses: actions/checkout@v4
- name: Prepare
run: |
bash ./scripts/ci-install.sh
make formatlua
git diff --exit-code
- name: Lint
run: make checklua
queries:
name: Lint query files
runs-on: ubuntu-slim
steps:
- uses: actions/checkout@v6
- name: Format
run: |
nvim --headless -c "TSInstallSync query" -c "q"
nvim -l scripts/format-queries.lua
make formatquery
git diff --exit-code
- name: Lint
run: make lintquery
readme:
name: Lint docs
runs-on: ubuntu-slim
steps:
- uses: actions/checkout@v6
- name: Check SUPPORTED_LANGUAGES
run: |
make docs
git diff --exit-code

View file

@ -1,24 +0,0 @@
name: "release"
on:
push:
tags: # Will upload to luarocks.org
- "*"
pull_request: # Will test a local install without uploading to luarocks.org
paths:
- 'contrib/*.rockspec'
- .github/workflows/release.yml
jobs:
luarocks-upload:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: nvim-neorocks/luarocks-tag-release@v5
env:
LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }}
with:
name: nvim-treesitter
detailed_description: |
The goal of nvim-treesitter is both to provide a simple and easy way to use the interface for tree-sitter in Neovim
and to provide some basic functionality such as highlighting based on it.
template: contrib/nvim-treesitter-luarocks.template

58
.github/workflows/test-core.yml vendored Normal file
View file

@ -0,0 +1,58 @@
on:
workflow_call:
inputs:
type:
type: string
workflow_dispatch:
defaults:
run:
shell: bash
jobs:
check_compilation:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
nvim_tag: [stable, nightly]
name: ${{matrix.nvim_tag}} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
NVIM: ${{ matrix.os == 'windows-latest' && 'nvim-win64\\bin\\nvim.exe' || 'nvim' }}
steps:
- uses: actions/checkout@v6
- uses: tree-sitter/setup-action/cli@v2
- name: Install and prepare Neovim
env:
NVIM_TAG: ${{ matrix.nvim_tag }}
run: |
bash ./scripts/ci-install.sh
- if: inputs.type == 'build'
name: Compile parsers
run: $NVIM -l ./scripts/install-parsers.lua --max-jobs=10
- if: inputs.type == 'generate'
name: Generate and compile parsers
run: $NVIM -l ./scripts/install-parsers.lua --generate --max-jobs=2
- name: Check parsers
run: $NVIM -l ./scripts/check-parsers.lua
- name: Check queries (nvim)
if: ${{ matrix.os == 'windows-latest' }}
run: $NVIM -l ./scripts/check-queries.lua
- name: Check queries (tsqueryls)
if: ${{ matrix.os != 'windows-latest' }}
run: make checkquery
- name: Run highlight tests
if: ${{ matrix.os != 'windows-latest' }}
run: make tests TESTS=query NVIM_BIN=$NVIM
- name: Run indents tests
if: ${{ matrix.os != 'windows-latest' }}
run: make tests TESTS=indent NVIM_BIN=$NVIM

20
.github/workflows/test-generate.yml vendored Normal file
View file

@ -0,0 +1,20 @@
name: Tests
on:
pull_request:
types: [unlabeled, labeled, opened, synchronize, reopened]
branches:
- "main"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-generate-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
check_compilation:
name: Generate
if: contains(github.event.pull_request.labels.*.name, 'ci:generate') || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/test-core.yml
with:
type: "generate"

View file

@ -1,88 +1,21 @@
name: Test queries
name: Tests
on:
push:
branches:
- "master"
- "main"
pull_request:
branches:
- "master"
- "main"
workflow_dispatch:
# Cancel any in-progress CI runs for a PR if it is updated
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
cancel-in-progress: true
defaults:
run:
shell: bash
group: ${{ github.workflow }}-build-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
check_compilation:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-14]
cc: [gcc, clang]
nvim_tag: [v0.10.4]
exclude:
- os: ubuntu-latest
cc: clang
nvim_tag: v0.10.4
- os: macos-14
cc: gcc
nvim_tag: v0.10.4
- os: windows-latest
cc: clang
nvim_tag: v0.10.4
include:
- os: windows-latest
cc: cl
nvim_tag: nightly
- os: ubuntu-latest
cc: gcc
nvim_tag: nightly
name: Parser compilation
runs-on: ${{ matrix.os }}
env:
CC: ${{ matrix.cc }}
NVIM: ${{ matrix.os == 'windows-latest' && 'nvim-win64\\bin\\nvim.exe' || 'nvim' }}
ALLOWED_INSTALLATION_FAILURES: ${{ matrix.os == 'windows-latest' && 'rnoweb' }}
steps:
- uses: actions/checkout@v4
- uses: tree-sitter/setup-action/cli@v1
- uses: ilammy/msvc-dev-cmd@v1
- name: Install and prepare Neovim
env:
NVIM_TAG: ${{ matrix.nvim_tag }}
run: |
bash ./scripts/ci-install.sh
- name: Setup Parsers Cache
id: parsers-cache
uses: actions/cache@v4
with:
path: |
./parser/
~/AppData/Local/nvim/pack/nvim-treesitter/start/nvim-treesitter/parser/
key: parsers-${{ join(matrix.*, '-') }}-${{ hashFiles(
'./lockfile.json',
'./lua/nvim-treesitter/install.lua',
'./lua/nvim-treesitter/parsers.lua',
'./lua/nvim-treesitter/shell_command_selectors.lua') }}
- name: Compile parsers
run: $NVIM --headless -c "lua require'nvim-treesitter.install'.prefer_git=false" -c "TSInstallSync all" -c "q"
- name: Post compile Windows
if: runner.os == 'Windows'
run: cp -r ~/AppData/Local/nvim/pack/nvim-treesitter/start/nvim-treesitter/parser/* parser
- name: Check query files
run: $NVIM -l scripts/check-queries.lua
name: Build
uses: ./.github/workflows/test-core.yml
with:
type: "build"

View file

@ -1,64 +0,0 @@
name: Tests
on:
push:
branches:
- "master"
pull_request:
branches:
- "master"
# Cancel any in-progress CI runs for a PR if it is updated
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
cancel-in-progress: true
jobs:
check_compilation:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
cc: [gcc]
name: Run tests
runs-on: ${{ matrix.os }}
env:
CC: ${{ matrix.cc }}
steps:
- uses: actions/checkout@v4
- uses: tree-sitter/setup-action/cli@v1
- name: Test Dependencies
run: |
mkdir -p ~/.local/share/nvim/site/pack/plenary.nvim/start
cd ~/.local/share/nvim/site/pack/plenary.nvim/start
git clone https://github.com/nvim-lua/plenary.nvim
curl -L https://github.com/theHamsta/highlight-assertions/releases/download/v0.1.6/highlight-assertions_v0.1.6_x86_64-unknown-linux-gnu.tar.gz | tar -xz
cp highlight-assertions /usr/local/bin
- name: Install and prepare Neovim
env:
NVIM_TAG: v0.10.4
run: |
bash ./scripts/ci-install.sh
- name: Setup Parsers Cache
id: parsers-cache
uses: actions/cache@v4
with:
path: |
./parser/
~/AppData/Local/nvim/pack/nvim-treesitter/start/nvim-treesitter/parser/
key: parsers-${{ join(matrix.*, '-') }}-${{ hashFiles(
'./lockfile.json',
'./lua/nvim-treesitter/install.lua',
'./lua/nvim-treesitter/parsers.lua',
'./lua/nvim-treesitter/shell_selectors.lua') }}
- name: Compile parsers Unix like
run: |
nvim --headless -c "TSInstallSync all" -c "q"
- name: Tests
run: PATH=/usr/local/bin:$PATH ./scripts/run_tests.sh

View file

@ -1,58 +0,0 @@
name: Update lockfile
on:
schedule:
- cron: "30 6 * * 6"
workflow_dispatch:
jobs:
update-lockfile:
name: Update lockfile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: master
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ vars.TOKEN_ID }}
private-key: ${{ secrets.TOKEN_PRIVATE_KEY }}
- name: Prepare
env:
NVIM_TAG: stable
run: |
wget https://github.com/josephburnett/jd/releases/download/v1.7.1/jd-amd64-linux
mv jd-amd64-linux /tmp/jd
chmod +x /tmp/jd
bash scripts/ci-install.sh
- name: Update parsers
env:
SKIP_LOCKFILE_UPDATE_FOR_LANGS: "bp,devicetree,dhall,elm,enforce,git_config,nickel,rescript,rust,slint,sql,t32,templ,typespec,verilog,wit"
run: |
cp lockfile.json /tmp/old_lockfile.json
nvim -l scripts/write-lockfile.lua
# Pretty print
cp lockfile.json /tmp/lockfile.json
cat /tmp/lockfile.json | jq --sort-keys > lockfile.json
UPDATED_PARSERS=$(/tmp/jd -f merge /tmp/old_lockfile.json lockfile.json | jq -r 'keys | join(", ")')
echo "UPDATED_PARSERS=$UPDATED_PARSERS" >> $GITHUB_ENV
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
token: ${{ steps.app-token.outputs.token }}
sign-commits: true
commit-message: "bot(lockfile): update ${{ env.UPDATED_PARSERS }}"
title: "Update lockfile.json: ${{ env.UPDATED_PARSERS }}"
body: "[beep boop](https://github.com/peter-evans/create-pull-request)"
branch: update-lockfile-pr
base: ${{ github.head_ref }}
- name: Enable Pull Request Automerge
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: gh pr merge --rebase --auto update-lockfile-pr

60
.github/workflows/update-parsers.yml vendored Normal file
View file

@ -0,0 +1,60 @@
name: Update parsers
on:
schedule:
- cron: "30 6 * * 6"
workflow_dispatch:
env:
BIN_DIR: ${{ github.workspace }}/bin
jobs:
update-parsers:
strategy:
fail-fast: false
matrix:
tier: [1, 2]
name: Update parsers tier ${{ matrix.tier }}
runs-on: ubuntu-slim
steps:
- uses: actions/checkout@v6
with:
ref: main
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ vars.TOKEN_ID }}
private-key: ${{ secrets.TOKEN_PRIVATE_KEY }}
- name: Add $BIN_DIR to PATH
run: echo "$BIN_DIR" >> $GITHUB_PATH
- name: Prepare
env:
NVIM_TAG: nightly
run: |
bash scripts/ci-install.sh
wget --directory-prefix="$BIN_DIR" https://github.com/JohnnyMorganz/StyLua/releases/latest/download/stylua-linux-x86_64.zip
(cd "$BIN_DIR"; unzip stylua*.zip)
- name: Update parsers
run: ./scripts/update-parsers.lua --tier=${{ matrix.tier }}
- name: Create Pull Request
uses: peter-evans/create-pull-request@v8
with:
add-paths: lua/nvim-treesitter/parsers.lua
token: ${{ steps.app-token.outputs.token }}
sign-commits: true
commit-message: "bot(parsers): update ${{ env.UPDATED_PARSERS }}"
title: "Update parsers (tier ${{ matrix.tier }}): ${{ env.UPDATED_PARSERS }}"
body: "[beep boop](https://github.com/peter-evans/create-pull-request)"
branch: update-parsers-tier-${{ matrix.tier }}
base: ${{ github.head_ref }}
- name: Enable Pull Request Automerge
if: ${{ matrix.tier == 2 }}
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: gh pr merge --rebase --auto update-parsers-tier-2

View file

@ -1,46 +0,0 @@
name: Update README
on:
push:
branches:
- master
workflow_dispatch:
jobs:
update-readme:
name: Update README
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ vars.TOKEN_ID }}
private-key: ${{ secrets.TOKEN_PRIVATE_KEY }}
- name: Prepare
env:
NVIM_TAG: stable
run: |
bash ./scripts/ci-install.sh
- name: Check README
run: |
nvim -l scripts/update-readme.lua || echo 'Needs update'
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
token: ${{ steps.app-token.outputs.token }}
sign-commits: true
commit-message: "bot(readme): update"
title: Update README
body: "[beep boop](https://github.com/peter-evans/create-pull-request)"
branch: update-readme-pr
base: ${{ github.head_ref }}
- name: Enable Pull Request Automerge
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: gh pr merge --rebase --auto update-readme-pr

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
.test-deps
doc/tags
.luacheckcache
/tags

View file

@ -1,21 +0,0 @@
-- Rerun tests only if their modification time changed.
cache = true
codes = true
exclude_files = {
"tests/indent/lua/"
}
-- Glorious list of warnings: https://luacheck.readthedocs.io/en/stable/warnings.html
ignore = {
"212", -- Unused argument, In the case of callback function, _arg_name is easier to understand than _, so this option is set to off.
"411", -- Redefining a local variable.
"412", -- Redefining an argument.
"422", -- Shadowing an argument
"122" -- Indirectly setting a readonly global
}
-- Global objects defined by the C code
read_globals = {
"vim",
}

View file

@ -5,12 +5,14 @@
},
"workspace": {
"library": [
"lua",
"$VIMRUNTIME",
"${3rd}/luv/library",
"${3rd}/busted/library"
],
"checkThirdParty": false
"ignoreDir": [
".test-deps",
"tests"
],
"checkThirdParty": "Disable"
},
"diagnostics": {
"groupFileStatus": {

View file

@ -1,6 +1,6 @@
column_width = 120
column_width = 100
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 2
quote_style = "AutoPreferDouble"
call_parentheses = "None"
quote_style = "AutoPreferSingle"
call_parentheses = "Always"

405
.tsqueryrc.json Normal file
View file

@ -0,0 +1,405 @@
{
"$schema": "https://raw.githubusercontent.com/ribru17/ts_query_ls/refs/heads/master/schemas/config.json",
"parser_install_directories": ["${HOME}/.local/share/nvim/site/parser"],
"supported_abi_versions": {
"start": 13,
"end": 15
},
"parser_aliases": {
"html_tags": "html",
"ecma": "javascript",
"jsx": "javascript"
},
"valid_captures": {
"highlights": {
"variable": "various variable names",
"variable.builtin": "built-in variable names (e.g. `this`)",
"variable.parameter": "parameters of a function",
"variable.parameter.builtin": "special parameters (e.g. `_`, `it`)",
"variable.member": "object and struct fields",
"constant": "constant identifiers",
"constant.builtin": "built-in constant values",
"constant.macro": "constants defined by the preprocessor",
"module": "modules or namespaces",
"module.builtin": "built-in modules or namespaces",
"label": "GOTO and other labels (e.g. `label:` in C), including heredoc labels",
"string": "string literals",
"string.documentation": "string documenting code (e.g. Python docstrings)",
"string.regexp": "regular expressions",
"string.escape": "escape sequences",
"string.special": "other special strings (e.g. dates)",
"string.special.symbol": "symbols or atoms",
"string.special.url": "URIs (e.g. hyperlinks)",
"string.special.path": "filenames",
"character": "character literals",
"character.special": "special characters (e.g. wildcards)",
"boolean": "boolean literals",
"number": "numeric literals",
"number.float": "floating-point number literals",
"type": "type or class definitions and annotations",
"type.builtin": "built-in types",
"type.definition": "identifiers in type definitions (e.g. `typedef <type> <identifier>` in C)",
"attribute": "attribute annotations (e.g. Python decorators, Rust lifetimes)",
"attribute.builtin": "builtin annotations (e.g. `@property` in Python)",
"property": "the key in key/value pairs",
"function": "function definitions",
"function.builtin": "built-in functions",
"function.call": "function calls",
"function.macro": "preprocessor macros",
"function.method": "method definitions",
"function.method.call": "method calls",
"constructor": "constructor calls and definitions",
"operator": "symbolic operators (e.g. `+` / `*`)",
"keyword": "keywords not fitting into specific categories",
"keyword.coroutine": "keywords related to coroutines (e.g. `go` in Go, `async/await` in Python)",
"keyword.function": "keywords that define a function (e.g. `func` in Go, `def` in Python)",
"keyword.operator": "operators that are English words (e.g. `and` / `or`)",
"keyword.import": "keywords for including or exporting modules (e.g. `import` / `from` in Python)",
"keyword.type": "keywords describing namespaces and composite types (e.g. `struct`, `enum`)",
"keyword.modifier": "keywords modifying other constructs (e.g. `const`, `static`, `public`)",
"keyword.repeat": "keywords related to loops (e.g. `for` / `while`)",
"keyword.return": "keywords like `return` and `yield`",
"keyword.debug": "keywords related to debugging",
"keyword.exception": "keywords related to exceptions (e.g. `throw` / `catch`)",
"keyword.conditional": "keywords related to conditionals (e.g. `if` / `else`)",
"keyword.conditional.ternary": "ternary operator (e.g. `?` / `:`)",
"keyword.directive": "various preprocessor directives & shebangs",
"keyword.directive.define": "preprocessor definition directives",
"punctuation.delimiter": "delimiters (e.g. `;` / `.` / `,`)",
"punctuation.bracket": "brackets (e.g. `()` / `{}` / `[]`)",
"punctuation.special": "special symbols (e.g. `{}` in string interpolation)",
"comment": "line and block comments",
"comment.documentation": "comments documenting code",
"comment.error": "error-type comments (e.g. `ERROR`, `FIXME`, `DEPRECATED`)",
"comment.warning": "warning-type comments (e.g. `WARNING`, `FIX`, `HACK`)",
"comment.todo": "todo-type comments (e.g. `TODO`, `WIP`)",
"comment.note": "note-type comments (e.g. `NOTE`, `INFO`, `XXX`)",
"markup.strong": "bold text",
"markup.italic": "italic text",
"markup.strikethrough": "struck-through text",
"markup.underline": "underlined text (only for literal underline markup!)",
"markup.heading": "headings, titles (including markers)",
"markup.heading.1": "top-level heading",
"markup.heading.2": "section heading",
"markup.heading.3": "subsection heading",
"markup.heading.4": "and so on",
"markup.heading.5": "and so forth",
"markup.heading.6": "six levels ought to be enough for anybody",
"markup.quote": "block quotes",
"markup.math": "math environments (e.g. `$ ... $` in LaTeX)",
"markup.link": "text references, footnotes, citations, etc.",
"markup.link.label": "link, reference descriptions",
"markup.link.url": "URL-style links",
"markup.raw": "literal or verbatim text (e.g. inline code)",
"markup.raw.block": "literal or verbatim text as a stand-alone block ; (use priority 90 for blocks with injections)",
"markup.list": "list markers",
"markup.list.checked": "checked todo-style list markers",
"markup.list.unchecked": "unchecked todo-style list markers",
"diff.plus": "added text (for diff files)",
"diff.minus": "deleted text (for diff files)",
"diff.delta": "changed text (for diff files)",
"tag": "XML-style tag names (and similar)",
"tag.builtin": "builtin tag names (e.g. HTML5 tags)",
"tag.attribute": "XML-style tag attributes",
"tag.delimiter": "XML-style tag delimiters",
"conceal": "captures that are only meant to be concealed",
"spell": "for defining regions to be spellchecked",
"nospell": "for defining regions that should NOT be spellchecked",
"none": "completely disable the highlight"
},
"injections": {
"injection.content": "indicates that the captured node should have its contents re-parsed using another language",
"injection.language": "indicates that the captured nodes text may contain the name of a language that should be used to re-parse the `@injection.content`",
"injection.filename": "indicates that the captured nodes text may contain a filename; the corresponding filetype is then looked-up up via `vim.filetype.match()` and treated as the name of a language that should be used to re-parse the `@injection.content`"
},
"folds": {
"fold": "fold this node"
},
"indents": {
"indent.begin": "Specifies that the next line should be indented. Multiple indents on the same line get collapsed. Indent can also have `indent.immediate` set using a `#set!` directive, which permits the next line to indent even when the block intended to be indented has no content yet, improving interactive typing.",
"indent.end": "Used to specify that the indented region ends and any text subsequent to the capture should be dedented.",
"indent.align": "Specifies aligned indent blocks (like python aligned/hanging indent). Specify the delimiters with `indent.open_delimiter` and `indent.close_delimiter` metadata. For some languages, the last line of an `indent.align` block must not be the same indent as the natural next line, which can be controlled by setting `indent.avoid_last_matching_next`.",
"indent.dedent": "Specifies dedenting starting on the next line.",
"indent.branch": "Used to specify that a dedented region starts at the line including the captured nodes.",
"indent.ignore": "Specifies that indentation should be ignored for this node.",
"indent.auto": "Behaves like 'autoindent' buffer option.",
"indent.zero": "Sets indentation for this node to zero (no indentation)."
},
"locals": {
"local.definition": "various definitions",
"local.definition.constant": "constants",
"local.definition.function": "functions",
"local.definition.method": "methods",
"local.definition.var": "variables",
"local.definition.parameter": "parameters",
"local.definition.macro": "preprocessor macros",
"local.definition.type": "types or classes",
"local.definition.field": "fields or properties",
"local.definition.enum": "enumerations",
"local.definition.namespace": "modules or namespaces",
"local.definition.import": "imported names",
"local.definition.associated": "the associated type of a variable",
"local.scope": "scope block",
"local.reference": "identifier reference"
}
},
"valid_predicates": {
"eq": {
"any": true,
"parameters": [
{
"type": "capture",
"arity": "required"
},
{
"type": "any",
"arity": "required"
}
],
"description": "checks for equality between two nodes, or a node and a string"
},
"any-of": {
"parameters": [
{
"type": "capture",
"arity": "required"
},
{
"type": "string",
"arity": "required"
},
{
"type": "string",
"arity": "required"
},
{
"type": "string",
"arity": "variadic"
}
],
"description": "match any of the given strings against the text corresponding to a node"
},
"contains": {
"any": true,
"parameters": [
{
"type": "capture",
"arity": "required"
},
{
"type": "string",
"arity": "required"
},
{
"type": "string",
"arity": "variadic"
}
],
"description": "match a string against parts of the text corresponding to a node"
},
"match": {
"any": true,
"parameters": [
{
"type": "capture",
"arity": "required"
},
{
"type": "string",
"arity": "required"
}
],
"description": "Match a regexp against the text corresponding to a node"
},
"lua-match": {
"any": true,
"parameters": [
{
"type": "capture",
"arity": "required"
},
{
"type": "string",
"arity": "required"
}
],
"description": "match a Lua pattern against the text corresponding to a node"
},
"has-ancestor": {
"parameters": [
{
"type": "capture",
"arity": "required"
},
{
"type": "string",
"arity": "required",
"constraint": "named_node"
},
{
"type": "string",
"arity": "variadic",
"constraint": "named_node"
}
],
"description": "match any of the given node types against all ancestors of a node"
},
"has-parent": {
"parameters": [
{
"type": "capture",
"arity": "required"
},
{
"type": "string",
"arity": "required",
"constraint": "named_node"
},
{
"type": "string",
"arity": "variadic",
"constraint": "named_node"
}
],
"description": "match any of the given node types against the direct ancestor of a node"
},
"kind-eq": {
"parameters": [
{
"type": "capture",
"arity": "required"
},
{
"type": "string",
"arity": "required",
"constraint": "named_node"
},
{
"type": "string",
"arity": "variadic",
"constraint": "named_node"
}
],
"description": "checks whether a capture corresponds to a given set of nodes"
}
},
"valid_directives": {
"set": {
"parameters": [
{
"type": "any",
"arity": "required"
},
{
"type": "any",
"arity": "optional"
},
{
"type": "any",
"arity": "optional"
}
],
"description": "sets key/value metadata for a specific match or capture"
},
"offset": {
"parameters": [
{
"type": "capture",
"arity": "required"
},
{
"type": "string",
"arity": "required",
"constraint": "integer"
},
{
"type": "string",
"arity": "required",
"constraint": "integer"
},
{
"type": "string",
"arity": "required",
"constraint": "integer"
},
{
"type": "string",
"arity": "required",
"constraint": "integer"
}
],
"description": "Takes the range of the captured node and applies an offset. This will set a new range in the form of a list like { {start_row}, {start_col}, {end_row}, {end_col} } for the captured node with `capture_id` as `metadata[capture_id].range`."
},
"gsub": {
"parameters": [
{
"type": "capture",
"arity": "required"
},
{
"type": "string",
"arity": "required"
},
{
"type": "string",
"arity": "required"
}
],
"description": "Transforms the content of the node using a Lua pattern. This will set a new `metadata[capture_id].text`."
},
"trim": {
"parameters": [
{
"type": "capture",
"arity": "required"
},
{
"type": "string",
"arity": "optional",
"constraint": {
"enum": ["0", "1"]
}
},
{
"type": "string",
"arity": "optional",
"constraint": {
"enum": ["0", "1"]
}
},
{
"type": "string",
"arity": "optional",
"constraint": {
"enum": ["0", "1"]
}
},
{
"type": "string",
"arity": "optional",
"constraint": {
"enum": ["0", "1"]
}
}
],
"description": "Trims whitespace from the node. Sets a new `metadata[capture_id].range`. Takes a capture ID and, optionally, four integers to customize trimming behavior (`1` meaning trim, `0` meaning don't trim). When only given a capture ID, trims blank lines (lines that contain only whitespace, or are empty) from the end of the node (for backwards compatibility). Can trim all whitespace from both sides of the node if parameters are given."
}
}
}

View file

@ -1,79 +1,103 @@
# Contributing to `nvim-treesitter`
First of all, thank you very much for contributing to `nvim-treesitter`.
The main parts of `nvim-treesitter` are
* a curated list of [parsers](#Parsers);
* a collection of [queries](#Queries).
If you haven't already, you should really come and reach out to us on our
[Matrix channel], so we can help you with any question you might have!
Before describing these in detail, some general advice:
* Some basic knowledge of how tree-sitter works is assumed; we recommend reading
- the [upstream documentation](https://tree-sitter.github.io/tree-sitter/);
- [Neovim's documentation](https://neovim.io/doc/user/treesitter.html#treesitter).
* There are dedicated Matrix channels for questions and general help:
- [#nvim-treesitter](https://matrix.to/#/#nvim-treesitter:matrix.org) for questions specific to Neovim's implementation and the queries here;
- [#tree-sitter](https://matrix.to/#/#tree-sitter-chat:matrix.org) for general questions regarding treesitter queries and the `tree-sitter` CLI.
As you know, `nvim-treesitter` is roughly split in two parts:
## Parsers
- Parser configurations : for various things like `locals`, `highlights`
- What we like to call _modules_ : tiny Lua modules that provide a given feature, based on parser configurations
>[!IMPORTANT]
> To qualify for inclusion, a parser must meet the following criteria:
> * correspond to a filetype detected by Neovim (nightly)
> * feature complete, tested by users, and actively maintained (according to maintainer discretion)
> * hosted or mirrored on Github (other codeforges are not reliable enough for CI)
> * covered by CI using [upstream workflows](https://github.com/tree-sitter/workflows)
> * provide reference queries covered by a [`ts_query_ls` workflow](https://github.com/tree-sitter-grammars/template/blob/9c46d09d688d27c7aef31c2b32f50260de4e7906/.github/workflows/ci.yml#L69-L86)
> * if the repo contains a `src/parser.c`, it must support the latest ABI
> * if the repo does _not_ contain a `src/parser.c`, it must contain an up-to-date `src/grammar.json`
> * if the repo contains an external scanner, it must be written in C99
>
> Tier 1 parsers (preferred) in addition need to
> * make regular releases following semver (_patch_ for fixes not affecting queries; _minor_ for changes introducing new nodes or patterns; _major_ for changes removing nodes or previously valid patterns)
> * provide WASM release artifacts
Depending on which part of the plugin you want to contribute to, please read the appropriate section.
To add a new parser, edit the following files:
## Style Checks and Tests
1. In `lua/parsers.lua`, add an entry to the returned table of the following form:
We haven't implemented any functional tests yet. Feel free to contribute.
However, we check code style with `luacheck` and `stylua`!
Please install luacheck and activate our `pre-push` hook to automatically check style before
every push:
```bash
luarocks install luacheck
cargo install stylua
ln -s ../../scripts/pre-push .git/hooks/pre-push
```lua
zimbu = {
install_info = {
url = 'https://github.com/zimbulang/tree-sitter-zimbu', -- git repo; use `path` for local path
revision = 'v2.1', -- tag or commit hash
-- optional entries:
branch = 'develop', -- only needed if different from default branch
location = 'parser', -- only needed if the parser is in subdirectory of a "monorepo"
generate = true, -- only needed if repo does not contain pre-generated src/parser.c
},
maintainers = { '@me' }, -- the _query_ maintainers
tier = 1, -- stable: track versioned releases instead of latest commit
-- optional entries:
requires = { 'vim' }, -- if the queries inherit from another language
readme_note = "an example language",
}
```
## Adding new modules
>[!IMPORTANT]
> The "maintainers" here refers to the person maintaining the **queries** in `nvim-treesitter`, not the parser maintainers (who likely don't use Neovim). The maintainers' duty is to review issues and PRs related to the query and to keep them updated with respect to parser changes.
If you want to see a new functionality added to `nvim-treesitter` feel free to first open an issue
to that we can track our solution!
Thus far, there is basically two types of modules:
2. If the parser name is not the same as the Vim filetype, add an entry to the `filetypes` table in `plugin/filetypes.lua`:
- Little modules (like `incremental selection`) that are built in `nvim-treesitter`, we call them
`builtin modules`.
- Bigger modules (like `completion-treesitter`, or `nvim-tree-docs`), or modules that integrate
with other plugins, that we call `remote modules`.
```lua
zimbu = { 'zu' },
```
In any case, you can build your own module! To help you started in the process, we have a template
repository designed to build new modules [here](https://github.com/nvim-treesitter/module-template).
Feel free to use it, and contact us over on our
on the "Neovim tree-sitter" [Matrix channel].
3. Update the list of [supported languages] by running `make docs` (or `./scripts/update-readme.lua` if on Windows).
## Parser configurations
4. Test if both `:TSInstall zimbu` and `:TSInstallFromGrammar zimbu` work without errors (`:checkhealth treesitter` or `./scripts/check-parsers.lua zimbu`).
Contributing to parser configurations is basically modifying one of the `queries/*/*.scm`.
Each of these `scheme` files contains a _tree-sitter query_ for a given purpose.
Before going any further, we highly suggest that you [read more about tree-sitter queries](https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries).
>[!IMPORTANT]
> You also need to add queries in order for the parser to actually be useful!
Each query has an appropriate name, which is then used by modules to extract data from the syntax tree.
For now these are the types of queries used by `nvim-treesitter`:
When you're done, open a Pull Request using the [provided template](.github/PULL_REQUEST_TEMPLATE/new_language.md), e.g. using `gh pr create -B main -T new_language`.
- `highlights.scm`: used for syntax highlighting, using the `highlight` module.
- `locals.scm`: used to extract keyword definitions, scopes, references, etc, using the `locals` module.
- `textobjects.scm`: used to define text objects.
- `folds.scm`: used to define folds.
- `injections.scm`: used to define injections.
## Queries
For these types there is a _norm_ you will have to follow so that features work fine.
Here are some global advices:
To add (or edit existing) queries, create a corresponding `runtime/queries/zimbu/*.scm` file:
- If your language is listed [here](https://github.com/nvim-treesitter/nvim-treesitter#supported-languages),
you can install the [playground plugin](https://github.com/nvim-treesitter/playground).
- If your language is listed [here](https://github.com/nvim-treesitter/nvim-treesitter#supported-languages),
you can debug and experiment with your queries there.
- If not, you should consider installing the [tree-sitter CLI](https://github.com/tree-sitter/tree-sitter/tree/master/cli),
you should then be able to open a local playground using `tree-sitter build-wasm && tree-sitter web-ui` within the
parsers repo.
- Examples of queries can be found in [queries/](queries/)
- Matches in the bottom will override queries that are above of them.
- `highlights.scm` used for syntax highlighting,
- `injections.scm` used to specify nodes whose content should be parsed as a different language;
- `folds.scm`; used to define folds;
- `locals.scm`: used to extract keyword definitions, scopes, references, etc. (not used in this plugin).
- `indents.scm`; used to control indentation.
See [tree-sitter queries] for a basic description of the query language. The following tools can be helpful when writing or editing queries:
* [ts_query_ls] is a language server for treesitter queries, which can validate, autocomplete, and format. This tool can also be used as an offline linter and formatter (accessible through `make lintquery`, `make checkquery`, `make formatquery` targets).
* Neovim's `:InspectTree` will show the parsed tree for a buffer and highlight the text corresponding to any given node (and vice versa).
* `:EditQuery` opens a "playground" where you can write query patterns and see which parts of the buffer are captured by each capture.
>[!IMPORTANT]
> The valid captures that can be used in queries is different for each editor, so you cannot just copy them, e.g., from Helix or the parser repositories. For Neovim, all valid captures are listed below. You can verify that your changes adhere to this by running `make lintquery`.
>[!IMPORTANT]
> Since grammars can change constantly, it is important to make sure that the patterns in a query are actually valid for the parser specified in nvim-treesitter's manifest. This can be verified using `make checkquery` (which requires the parser to be installed in the default directory(!) through `nvim-treesitter`). Opening the query in Neovim with the parser installed will also show all invalid patterns, either via [ts_query_ls] or Neovim's builtin query-linter.
>[!TIP]
> Before opening a PR, run `make query` to format, lint, and check all queries.
#### Inheriting languages
If your language is an extension of a language (TypeScript is an extension of JavaScript for
example), you can include the queries from your base language by adding the following _as the first
line of your file_.
line of your file_:
```query
; inherits: lang1,(optionallang)
@ -84,7 +108,7 @@ you can mark the language as optional (by putting it between parenthesis).
#### Formatting
All queries are expected to follow a standard format, with every node on a single line and indented by two spaces for each level of nesting. You can automatically format the bundled queries by running the provided formatter `./scripts/format-queries.lua` on a single file (ending in `.scm`) or directory to format.
All queries are expected to follow a standard format, with every node on a single line and indented by two spaces for each level of nesting. You can automatically format the bundled queries by running `make formatquery`.
Should you need to preserve a specific format for a node, you can exempt it (and all contained nodes) by placing before it
```query
@ -93,7 +117,10 @@ Should you need to preserve a specific format for a node, you can exempt it (and
### Highlights
As languages differ quite a lot, here is a set of captures available to you when building a `highlights.scm` query. Note that your color scheme needs to define (or link) these captures as highlight groups.
Syntax highlighting is specified in a `highlights.scm` query, which assigns treesitter nodes to captures that can be assigned a highlight group. This feature is implemented in Neovim and documented at [`:h treesitter-highlight`](https://neovim.io/doc/user/treesitter.html#treesitter-highlight).
Note that your color scheme needs to define (or link) these captures as highlight groups. You can use Neovim's built-in `:Inspect` function to see exactly which highlight groups are applied at a given position.
The valid captures are listed below.
#### Identifiers
@ -252,45 +279,202 @@ Mainly for markup languages.
#### Non-highlighting captures
```query
@none ; completely disable the highlight
@conceal ; captures that are only meant to be concealed
```
>[!TIP]
> * See [`:h tree-sitter-highlight-conceal`](https://neovim.io/doc/user/treesitter.html#treesitter-highlight-conceal).
> * The capture should be meaningful to allow proper highlighting when `set conceallevel=0`.
> * A conceal can be restricted to part of the capture via the [`#offset!` directive](https://neovim.io/doc/user/treesitter.html#treesitter-directive-offset%21).
```query
@spell ; for defining regions to be spellchecked
@nospell ; for defining regions that should NOT be spellchecked
```
The main types of nodes which are spell checked are:
- Comments
- Strings; where it makes sense. Strings that have interpolation or are typically used for non text purposes are not spell checked (e.g. bash).
>[!TIP]
> The main types of nodes that should be spell checked are
> - comments
> - strings; where it makes sense. Strings that have interpolation or are typically used for non text purposes are not spell checked (e.g. bash).
#### Predicates
Captures can be restricted according to node contents using [predicates](https://neovim.io/doc/user/treesitter.html#treesitter-predicates). For performance reasons, prefer earlier predicates in this list:
Captures can be restricted according to node contents using [predicates](https://neovim.io/doc/user/treesitter.html#treesitter-predicates).
1. `#eq?` (literal match)
2. `#any-of?` (one of several literal matches)
3. `#lua-match?` (match against a [Lua pattern](https://neovim.io/doc/user/luaref.html#lua-pattern))
4. `#match?`/`#vim-match?` (match against a [Vim regular expression](https://neovim.io/doc/user/pattern.html#regexp)
>[!IMPORTANT]
> For performance reasons, prefer earlier predicates in this list:
>
> 1. `#eq?` (literal match)
> 2. `#any-of?` (one of several literal matches)
> 3. `#lua-match?` (match against a [Lua pattern](https://neovim.io/doc/user/luaref.html#lua-pattern))
> 4. `#match?`/`#vim-match?` (match against a [Vim regular expression](https://neovim.io/doc/user/pattern.html#regexp)
#### Conceal
Besides those provided by Neovim, nvim-treesitter also implements
Captures can be concealed by setting the [`conceal` metadata](https://neovim.io/doc/user/treesitter.html#treesitter-highlight-conceal), e.g..,
```query
(fenced_code_block_delimiter @markup.raw.block (#set! conceal ""))
#kind-eq? ; checks whether a capture corresponds to a given set of nodes
#any-kind-eq? ; checks whether any of a list of captures corresponds to a given set of nodes
```
The capture should be meaningful to allow proper highlighting when `set conceallevel=0`. If the unconcealed capture should not be highlighted (e.g., because an earlier pattern handles this), you can use `@conceal`.
A conceal can be restricted to part of the capture via the [`#offset!` directive](https://neovim.io/doc/user/treesitter.html#treesitter-directive-offset%21).
#### Directives
Nodes contain metadata that can be modified via [directives](https://neovim.io/doc/user/treesitter.html#treesitter-directives).
#### Priority
Captures can be assigned a priority to control precedence of highlights via the
`#set! priority <number>` directive (see `:h treesitter-highlight-priority`).
The default priority for treesitter highlights is `100`; queries should only
set priorities between `90` and `120`, to avoid conflict with other sources of
highlighting (such as diagnostics or LSP semantic tokens).
`#set! priority <number>` directive (see [`:h treesitter-highlight-priority`](https://neovim.io/doc/user/treesitter.html#treesitter-highlight-priority)). This is useful for controlling conflicts with injected languages or when inheriting queries from other languages.
>[!NOTE]
> The default priority for treesitter highlights is `100`; queries should only
set priorities between `90` and `120`, to avoid conflict with other sources of highlighting (such as diagnostics or LSP semantic tokens).
>[!TIP]
> Precedence is also influenced by pattern order in a query file. If possible, try to achieve the correct result by reordering patterns before resorting to explicit priorities.
### Injections
Language injections are controlled by `injections.scm` queries, which specify nodes that should be parsed as a different language. This feature is implemented in Neovim and documented at
[`:h treesitter-language-injections](https://neovim.io/doc/user/treesitter.html#treesitter-language-injections).
The valid captures are:
```query
@injection.language ; dynamic detection of the injection language (i.e. the text of the captured node describes the language)
@injection.content ; region for the dynamically detected language
@injection.filename ; indicates that the captured nodes text may contain a filename; the corresponding filetype is then looked-up up via vim.filetype.match() and treated as the name of a language that should be used to re-parse the `@injection.content`
```
>[!TIP]
> When writing injection queries, try to ensure that each captured node is only matched by a single pattern.
### Folds
You can define folds for a given language by adding a `folds.scm` query. This is implemented in Neovim. The only valid capture is `@fold`:
```query
(function_definition) @fold ; fold this node
```
Folds should be given to nodes with defined start and end delimiters/patterns, or to consecutive nodes which are part of the same conceptual "grouping", such as consecutive line comments or import statements. The following items are valid fold candidates:
- Function/method definitions
- Class/interface/trait definitions
- Switch/match statements, and individual match arms
- Execution blocks (such as those found in conditional statements or loops)
- Parameter/argument lists
- Array/object/string expressions
- Consecutive import statements, consecutive line comments
The following items would *not* be valid fold candidates:
- Multiline assignment statements
- Multiline property access expressions
As a rule of thumb, these highlight captures usually reside in or around objects which should be folded:
- `@function`, `@function.method`
- `@keyword.import`, `@keyword.conditional`, `@keyword.repeat`
- `@comment`, `@comment.documentation`
- `@string`, `@string.documentation`
- `@markup.heading.x`, `@markup.list`
### Indents
>[!WARNING]
> Treesitter-based indentation is still experimental and likely to have breaking changes in the future.
Indentation for a language is controlled by `indents.scm` queries. The following captures can be used to set the indentation for nodes, either relative or absolute
* `@indent.begin` specifies that the next line should be indented. Multiple
indents on the same line get collapsed, e.g.,
```query
(
(if_statement)
(ERROR "else") @indent.begin
)
```
You can also `#set! indent.immediate` to permit the next line to indent even when the block intended to be indented has no content yet. (This can improve interactive typing.)
For example for Python,
```query
((if_statement) @indent.begin
(#set! indent.immediate 1))
```
will allow
```python
if True:<CR>
# Auto indent to here
```
* `@indent.end` is used to specify that the indented region ends and any text subsequent to the capture should be dedented.
* `@indent.branch` is used to specify that a dedented region starts at the line _including_ the captured nodes.
* `@indent.dedent` specifies dedenting starting on the _next_ line.
* `@indent.auto` behaves like Vim's [`autoindent`](https://neovim.io/doc/user/options.html#'autoindent') buffer option (copy whatever the indentation of previous line is when opening a new line after it).
* `@indent.ignore` specifies that no indent should be added to this node.
* `@indent.zero` sets the indentation of this node to 0 (i.e., removes _all_ indentation).
* `@indent.align` can be used to specify blocks that should have the same indentation.
This allows
```
foo(a,
b,
c)
```
as well as
```
foo(
a,
b,
c)
```
and
```
foo(
a,
b,
c
)
```
To specify the delimiters to align at, `#set! indent.open_delimiter` and
`indent.close_delimiter`, e.g.,
```query
((argument_list) @indent.align
(#set! indent.open_delimiter "(")
(#set! indent.close_delimiter ")"))
```
For some languages, the last line of an `indent.align` block must not be
the same indent as the natural next line.
For example in Python,
```python
if (a > b and
c < d):
pass
```
is not correct, whereas
```python
if (a > b and
c < d):
pass
```
would be correctly indented. This behavior may be selected by setting
`indent.avoid_last_matching_next`. For example,
```query
(if_statement
condition: (parenthesized_expression) @indent.align
(#set! indent.open_delimiter "(")
(#set! indent.close_delimiter ")")
(#set! indent.avoid_last_matching_next 1)
)
```
specifies that the last line of an `@indent.align` capture
should be additionally indented to avoid clashing with the indent of the first
line of the block inside an `if`.
### Locals
@ -298,7 +482,8 @@ Locals are used to keep track of definitions and references in local or global
scopes, see [upstream
documentation](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#local-variables).
Note that nvim-treesitter uses more specific subcaptures for definitions and
**does not use locals for highlighting**.
**does not use locals** (for highlighting or any other purpose). These queries
are only provided for limited backwards compatibility.
```query
@local.definition ; various definitions
@ -319,7 +504,7 @@ Note that nvim-treesitter uses more specific subcaptures for definitions and
@local.reference ; identifier reference
```
#### Definition Scope
#### Definition scope
You can set the scope of a definition by setting the `scope` property on the definition.
@ -345,57 +530,7 @@ Possible scope values are:
- `global`: The definition is valid in the root scope
- `local`: The definition is valid in the containing scope. This is the default behavior
### Folds
You can define folds for a given language by adding a `folds.scm` query :
```query
@fold ; fold this node
```
If the `folds.scm` query is not present, this will fall back to the `@local.scope` captures in the `locals`
query.
### Injections
Some captures are related to language injection (like markdown code blocks). They are used in `injections.scm`.
If you want to dynamically detect the language (e.g. for Markdown blocks) use the `@injection.language` to capture
the node describing the language and `@injection.content` to describe the injection region.
```query
@injection.language ; dynamic detection of the injection language (i.e. the text of the captured node describes the language)
@injection.content ; region for the dynamically detected language
```
For example, to inject javascript into HTML's `<script>` tag
```html
<script>someJsCode();</script>
```
```query
(script_element
(raw_text) @injection.content
(#set! injection.language "javascript")) ; set the parser language for @injection.content region to javascript
```
For regions that don't have a corresponding `@injection.language`, you need to manually set the language
through `(#set injection.language "lang_name")`
To combine all matches of a pattern as one single block of content, add `(#set! injection.combined)` to such pattern
### Indents
```query
@indent.begin ; indent children when matching this node
@indent.end ; marks the end of indented block
@indent.align ; behaves like python aligned/hanging indent
@indent.dedent ; dedent children when matching this node
@indent.branch ; dedent itself when matching this node
@indent.ignore ; do not indent in this node
@indent.auto ; behaves like 'autoindent' buffer option
@indent.zero ; sets this node at position 0 (no indent)
```
[Matrix channel]: https://matrix.to/#/#nvim-treesitter:matrix.org
[supported languages]: https://github.com/nvim-treesitter/nvim-treesitter/SUPPORTED_LANGUAGES.md
[tree-sitter queries]: https://tree-sitter.github.io/tree-sitter/using-parsers/queries/index.html
[ts_query_ls]: https://github.com/ribru17/ts_query_ls

144
Makefile
View file

@ -1,7 +1,139 @@
# https://github.com/luarocks/luarocks/wiki/Creating-a-Makefile-that-plays-nice-with-LuaRocks
build:
echo "Do nothing"
NVIM_VERSION ?= nightly
install:
mkdir -p $(INST_LUADIR)
cp -r lua/* $(INST_LUADIR)
DEPDIR ?= .test-deps
CURL ?= curl -sL --create-dirs
ifeq ($(shell uname -s),Darwin)
NVIM_ARCH ?= macos-arm64
LUALS_ARCH ?= darwin-arm64
STYLUA_ARCH ?= macos-aarch64
RUST_ARCH ?= aarch64-apple-darwin
else
NVIM_ARCH ?= linux-x86_64
LUALS_ARCH ?= linux-x64
STYLUA_ARCH ?= linux-x86_64
RUST_ARCH ?= x86_64-unknown-linux-gnu
endif
.DEFAULT_GOAL := all
# download test dependencies
NVIM := $(DEPDIR)/nvim-$(NVIM_ARCH)
NVIM_TARBALL := $(NVIM).tar.gz
NVIM_URL := https://github.com/neovim/neovim/releases/download/$(NVIM_VERSION)/$(notdir $(NVIM_TARBALL))
NVIM_BIN := $(NVIM)/nvim-$(NVIM_ARCH)/bin/nvim
NVIM_RUNTIME=$(NVIM)/nvim-$(NVIM_ARCH)/share/nvim/runtime
.PHONY: nvim
nvim: $(NVIM)
$(NVIM):
$(CURL) $(NVIM_URL) -o $(NVIM_TARBALL)
mkdir $@
tar -xf $(NVIM_TARBALL) -C $@
rm -rf $(NVIM_TARBALL)
EMMYLUALS := $(DEPDIR)/emmylua_check-$(LUALS_ARCH)
EMMYLUALS_TARBALL := $(EMMYLUALS).tar.gz
EMMYLUALS_URL := https://github.com/emmyluals/emmylua-analyzer-rust/releases/latest/download/$(notdir $(EMMYLUALS_TARBALL))
.PHONY: emmyluals
emmyluals: $(EMMYLUALS)
$(EMMYLUALS):
$(CURL) $(EMMYLUALS_URL) -o $(EMMYLUALS_TARBALL)
mkdir $@
tar -xf $(EMMYLUALS_TARBALL) -C $@
rm -rf $(EMMYLUALS_TARBALL)
STYLUA := $(DEPDIR)/stylua-$(STYLUA_ARCH)
STYLUA_TARBALL := $(STYLUA).zip
STYLUA_URL := https://github.com/JohnnyMorganz/StyLua/releases/latest/download/$(notdir $(STYLUA_TARBALL))
.PHONY: stylua
stylua: $(STYLUA)
$(STYLUA):
$(CURL) $(STYLUA_URL) -o $(STYLUA_TARBALL)
unzip $(STYLUA_TARBALL) -d $(STYLUA)
rm -rf $(STYLUA_TARBALL)
TSQUERYLS := $(DEPDIR)/ts_query_ls-$(RUST_ARCH)
TSQUERYLS_TARBALL := $(TSQUERYLS).tar.gz
TSQUERYLS_URL := https://github.com/ribru17/ts_query_ls/releases/latest/download/$(notdir $(TSQUERYLS_TARBALL))
.PHONY: tsqueryls
tsqueryls: $(TSQUERYLS)
$(TSQUERYLS):
$(CURL) $(TSQUERYLS_URL) -o $(TSQUERYLS_TARBALL)
mkdir $@
tar -xf $(TSQUERYLS_TARBALL) -C $@
rm -rf $(TSQUERYLS_TARBALL)
HLASSERT := $(DEPDIR)/highlight-assertions-$(RUST_ARCH)
HLASSERT_TARBALL := $(HLASSERT).tar.gz
HLASSERT_URL := https://github.com/nvim-treesitter/highlight-assertions/releases/latest/download/$(notdir $(HLASSERT_TARBALL))
.PHONY: hlassert
hlassert: $(HLASSERT)
$(HLASSERT):
$(CURL) $(HLASSERT_URL) -o $(HLASSERT_TARBALL)
mkdir $@
tar -xf $(HLASSERT_TARBALL) -C $@
rm -rf $(HLASSERT_TARBALL)
PLENTEST := $(DEPDIR)/plentest.nvim
.PHONY: plentest
plentest: $(PLENTEST)
$(PLENTEST):
git clone --filter=blob:none https://github.com/nvim-treesitter/plentest.nvim $(PLENTEST)
# actual test targets
.PHONY: lua
lua: formatlua checklua
.PHONY: formatlua
formatlua: $(STYLUA)
$(STYLUA)/stylua .
.PHONY: checklua
checklua: $(EMMYLUALS) $(NVIM)
VIMRUNTIME=$(NVIM_RUNTIME) $(EMMYLUALS)/emmylua_check --warnings-as-errors .
.PHONY: query
query: formatquery lintquery checkquery
.PHONY: lintquery
lintquery: $(TSQUERYLS)
$(TSQUERYLS)/ts_query_ls lint runtime/queries
.PHONY: formatquery
formatquery: $(TSQUERYLS)
$(TSQUERYLS)/ts_query_ls format runtime/queries
.PHONY: checkquery
checkquery: $(TSQUERYLS)
$(TSQUERYLS)/ts_query_ls check runtime/queries
.PHONY: docs
docs: $(NVIM)
$(NVIM_BIN) -l scripts/update-readme.lua
.PHONY: tests
tests: $(NVIM) $(HLASSERT) $(PLENTEST)
HLASSERT=$(HLASSERT)/highlight-assertions PLENTEST=$(PLENTEST) \
$(NVIM_BIN) --headless --clean -u scripts/minimal_init.lua \
-c "lua require('plentest').test_directory('tests/$(TESTS)', { minimal_init = './scripts/minimal_init.lua' })"
.PHONY: all
all: lua query docs tests
.PHONY: clean
clean:
rm -rf $(DEPDIR)

906
README.md
View file

@ -1,851 +1,187 @@
<div align="center">
<h1>nvim-treesitter</h1>
<p>
<a href="https://matrix.to/#/#nvim-treesitter:matrix.org">
<img alt="Matrix Chat" src="https://img.shields.io/matrix/nvim-treesitter:matrix.org" />
</a>
<a href="https://github.com/nvim-treesitter/nvim-treesitter/actions?query=workflow%3A%22Linting+and+style+checking%22+branch%3Amaster">
<img alt="Linting and Style" src="https://github.com/nvim-treesitter/nvim-treesitter/workflows/Linting%20and%20style%20checking/badge.svg" />
</a>
<a href="https://github.com/nvim-treesitter/nvim-treesitter/actions?query=workflow%3A%22Check+loading+of+syntax+files%22+branch%3Amaster">
<img alt="Syntax files" src="https://github.com/nvim-treesitter/nvim-treesitter/workflows/Check%20loading%20of%20syntax%20files/badge.svg" />
</a>
</p>
</div>
<h1 align="center">
<img src="https://github.com/nvim-treesitter/nvim-treesitter/assets/2361214/0513b223-c902-4f12-92ee-8ac4d8d6f41f" alt="nvim-treesitter">
</h1>
<div align="center">
<p>
<img src="assets/logo.png" align="center" alt="Logo" />
</p>
<p>
<a href="https://github.com/tree-sitter/tree-sitter">Treesitter</a>
configurations and abstraction layer for
<a href="https://github.com/neovim/neovim/">Neovim</a>.
</p>
<p>
<i>
Logo by <a href="https://github.com/steelsojka">@steelsojka</a>
</i>
</p>
</div>
The `nvim-treesitter` plugin provides
1. functions for installing, updating, and removing [**tree-sitter parsers**](SUPPORTED_LANGUAGES.md);
2. a collection of **queries** for enabling tree-sitter features built into Neovim for these languages;
3. a staging ground for [treesitter-based features](#Supported-features) considered for upstreaming to Neovim.
The goal of `nvim-treesitter` is both to provide a simple and easy way to use the interface for [tree-sitter](https://github.com/tree-sitter/tree-sitter) in Neovim and to provide some basic functionality such as highlighting based on it:
For details on these and how to help improving them, see [CONTRIBUTING.md](./CONTRIBUTING.md).
![example-cpp](https://user-images.githubusercontent.com/2361214/202753610-e923bf4e-e88f-494b-bb1e-d22a7688446f.png)
Traditional highlighting (left) vs Treesitter-based highlighting (right).
More examples can be found in [our gallery](https://github.com/nvim-treesitter/nvim-treesitter/wiki/Gallery).
**Warning: Treesitter and nvim-treesitter highlighting are an experimental feature of Neovim.
Please consider the experience with this plug-in as experimental until Tree-Sitter support in Neovim is stable!
We recommend using the nightly builds of Neovim if possible.
You can find the current roadmap [here](https://github.com/nvim-treesitter/nvim-treesitter/issues/4767).
The roadmap and all features of this plugin are open to change, and any suggestion will be highly appreciated!**
Nvim-treesitter is based on three interlocking features: [**language parsers**](#language-parsers), [**queries**](#adding-queries), and [**modules**](#available-modules), where _modules_ provide features e.g., highlighting based on _queries_ for syntax objects extracted from a given buffer by _language parsers_.
Users will generally only need to interact with parsers and modules as explained in the next section.
For more detailed information on setting these up, see ["Advanced setup"](#advanced-setup).
---
### Table of contents
- [Quickstart](#quickstart)
- [Supported languages](#supported-languages)
- [Available modules](#available-modules)
- [Advanced setup](#advanced-setup)
- [Extra features](#extra-features)
- [Troubleshooting](#troubleshooting)
---
>[!CAUTION]
> This is a full, incompatible, rewrite: Treat this as a different plugin you need to set up from scratch following the instructions below. If you can't or don't want to update, specify the [`master` branch](https://github.com/nvim-treesitter/nvim-treesitter/blob/master/README.md) (which is locked but will remain available for backward compatibility with Nvim 0.11).
# Quickstart
## Requirements
- **Neovim 0.10** or later ([nightly](https://github.com/neovim/neovim#install-from-source) recommended)
- `tar` and `curl` in your path (or alternatively `git`)
- A C compiler in your path and libstdc++ installed ([Windows users please read this!](https://github.com/nvim-treesitter/nvim-treesitter/wiki/Windows-support)).
- Neovim 0.12.0 or later (nightly)
- `tar` and `curl` in your path
- [`tree-sitter-cli`](https://github.com/tree-sitter/tree-sitter/blob/master/crates/cli/README.md) (0.26.1 or later, installed via your package manager, **not npm**)
- a C compiler in your path (see <https://docs.rs/cc/latest/cc/#compile-time-requirements>)
>[!IMPORTANT]
> The current **support policy** for Neovim is
> * the _latest_ [stable release](https://github.com/neovim/neovim/releases/tag/stable),
> * the _latest_ [nightly prerelease](https://github.com/neovim/neovim/releases/tag/nightly).
> Other versions may work but are neither tested nor considered for fixes.
## Installation
You can install `nvim-treesitter` with your favorite package manager (or using the native `package` feature of vim, see `:h packages`).
**NOTE: This plugin is only guaranteed to work with specific versions of language parsers** (as specified in the `lockfile.json`). **When upgrading the plugin, you must make sure that all installed parsers are updated to the latest version** via `:TSUpdate`.
It is strongly recommended to automate this; e.g., if you are using [vim-plug](https://github.com/junegunn/vim-plug), put this in your `init.vim` file:
```vim
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
```
For other plugin managers such as `packer.nvim`, see this [Installation page from the wiki](https://github.com/nvim-treesitter/nvim-treesitter/wiki/Installation) (Note that this page is community maintained).
## Language parsers
Treesitter uses a different _parser_ for every language, which needs to be generated via `tree-sitter-cli` from a `grammar.js` file, then compiled to a `.so` library that needs to be placed in neovim's `runtimepath` (typically under `parser/{language}.so`).
To simplify this, `nvim-treesitter` provides commands to automate this process.
If the language is already [supported by `nvim-treesitter`](#supported-languages), you can install it with
```vim
:TSInstall <language_to_install>
```
This command supports tab expansion.
You can also get a list of all available languages and their installation status with `:TSInstallInfo`.
Parsers not on this list can be added manually by following the steps described under ["Adding parsers"](#adding-parsers) below.
To make sure a parser is at the latest compatible version (as specified in `nvim-treesitter`'s `lockfile.json`), use `:TSUpdate {language}`. To update all parsers unconditionally, use `:TSUpdate all` or just `:TSUpdate`.
## Modules
Each module provides a distinct tree-sitter-based feature such as [highlighting](#highlight), [indentation](#indentation), or [folding](#folding); see [`:h nvim-treesitter-modules`](doc/nvim-treesitter.txt) or ["Available modules"](#available-modules) below for a list of modules and their options.
Following examples assume that you are configuring neovim with lua. If you are using vimscript, see `:h lua-heredoc`.
All modules are disabled by default and need to be activated explicitly in your `init.lua`, e.g., via
This plugin is only guaranteed to work with specific versions of language parsers** (as specified in the `parser.lua` table). **When upgrading the plugin, you must make sure that all installed parsers are updated to the latest version** via `:TSUpdate`.
It is strongly recommended to automate this; e.g., using the following spec with [lazy.nvim](https://github.com/folke/lazy.nvim):
```lua
require'nvim-treesitter.configs'.setup {
-- A list of parser names, or "all" (the listed parsers MUST always be installed)
ensure_installed = { "c", "lua", "vim", "vimdoc", "query", "markdown", "markdown_inline" },
-- Install parsers synchronously (only applied to `ensure_installed`)
sync_install = false,
-- Automatically install missing parsers when entering buffer
-- Recommendation: set to false if you don't have `tree-sitter` CLI installed locally
auto_install = true,
-- List of parsers to ignore installing (or "all")
ignore_install = { "javascript" },
---- If you need to change the installation directory of the parsers (see -> Advanced Setup)
-- parser_install_dir = "/some/path/to/store/parsers", -- Remember to run vim.opt.runtimepath:append("/some/path/to/store/parsers")!
highlight = {
enable = true,
-- NOTE: these are the names of the parsers and not the filetype. (for example if you want to
-- disable highlighting for the `tex` filetype, you need to include `latex` in this list as this is
-- the name of the parser)
-- list of language that will be disabled
disable = { "c", "rust" },
-- Or use a function for more flexibility, e.g. to disable slow treesitter highlight for large files
disable = function(lang, buf)
local max_filesize = 100 * 1024 -- 100 KB
local ok, stats = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(buf))
if ok and stats and stats.size > max_filesize then
return true
end
end,
-- Setting this to true will run `:h syntax` and tree-sitter at the same time.
-- Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
-- Using this option may slow down your editor, and you may see some duplicate highlights.
-- Instead of true it can also be a list of languages
additional_vim_regex_highlighting = false,
},
{
'nvim-treesitter/nvim-treesitter',
lazy = false,
build = ':TSUpdate'
}
```
Each module can also be enabled or disabled interactively through the following commands:
>[!IMPORTANT]
> This plugin does not support lazy-loading.
```vim
:TSBufEnable {module} " enable module on current buffer
:TSBufDisable {module} " disable module on current buffer
:TSEnable {module} [{ft}] " enable module on every buffer. If filetype is specified, enable only for this filetype.
:TSDisable {module} [{ft}] " disable module on every buffer. If filetype is specified, disable only for this filetype.
:TSModuleInfo [{module}] " list information about modules state for each filetype
## Setup
`nvim-treesitter` can be configured by calling `setup`. **You do not need to call `setup` for `nvim-treesitter` to work using default values.**
```lua
require('nvim-treesitter').setup {
-- Directory to install parsers and queries to (prepended to `runtimepath` to have priority)
install_dir = vim.fn.stdpath('data') .. '/site'
}
```
Parsers and queries can then be installed with
```lua
require('nvim-treesitter').install { 'rust', 'javascript', 'zig' }
```
(This is a no-op if the parsers are already installed.) Note that this function runs asynchronously; for synchronous installation in a script context ("bootstrapping"), you need to `wait()` for it to finish:
```lua
require('nvim-treesitter').install({ 'rust', 'javascript', 'zig' }):wait(300000) -- wait max. 5 minutes
```
Check [`:h nvim-treesitter-commands`](doc/nvim-treesitter.txt) for a list of all available commands.
It may be necessary to reload the buffer (e.g., via `:e`) after enabling a module interactively.
# Supported languages
For `nvim-treesitter` to support a specific feature for a specific language requires both a parser for that language and an appropriate language-specific query file for that feature.
The following is a list of languages for which a parser can be installed through `:TSInstall`; a checked box means that `nvim-treesitter` also contains queries at least for the `highlight` module.
A list of the currently supported languages can be found [on this page](SUPPORTED_LANGUAGES.md). If you wish to add a new language or improve the queries for an existing one, please see our [contributing guide](CONTRIBUTING.md).
Experimental parsers are parsers that have a maintainer but are not stable enough for
daily use yet.
# Supported features
We are looking for maintainers to add more parsers and to write query files for their languages. Check our [tracking issue](https://github.com/nvim-treesitter/nvim-treesitter/issues/2282) for open language requests.
`nvim-treesitter` provides queries for the following features. **These are not automatically enabled.**
<!--This section of the README is automatically updated by a CI job-->
<!--parserinfo-->
- [x] [ada](https://github.com/briot/tree-sitter-ada) (maintained by @briot)
- [x] [agda](https://github.com/tree-sitter/tree-sitter-agda) (maintained by @Decodetalkers)
- [x] [angular](https://github.com/dlvandenberg/tree-sitter-angular) (experimental, maintained by @dlvandenberg)
- [x] [apex](https://github.com/aheber/tree-sitter-sfapex) (maintained by @aheber, @xixiaofinland)
- [x] [arduino](https://github.com/ObserverOfTime/tree-sitter-arduino) (maintained by @ObserverOfTime)
- [x] [asm](https://github.com/RubixDev/tree-sitter-asm) (maintained by @RubixDev)
- [x] [astro](https://github.com/virchau13/tree-sitter-astro) (maintained by @virchau13)
- [x] [authzed](https://github.com/mleonidas/tree-sitter-authzed) (maintained by @mattpolzin)
- [ ] [awk](https://github.com/Beaglefoot/tree-sitter-awk)
- [x] [bash](https://github.com/tree-sitter/tree-sitter-bash) (maintained by @TravonteD)
- [x] [bass](https://github.com/vito/tree-sitter-bass) (maintained by @amaanq)
- [x] [beancount](https://github.com/polarmutex/tree-sitter-beancount) (maintained by @polarmutex)
- [x] [bibtex](https://github.com/latex-lsp/tree-sitter-bibtex) (maintained by @theHamsta, @clason)
- [x] [bicep](https://github.com/amaanq/tree-sitter-bicep) (maintained by @amaanq)
- [x] [bitbake](https://github.com/amaanq/tree-sitter-bitbake) (maintained by @amaanq)
- [x] [blade](https://github.com/EmranMR/tree-sitter-blade) (maintained by @calebdw)
- [x] [blueprint](https://gitlab.com/gabmus/tree-sitter-blueprint.git) (experimental, maintained by @gabmus)
- [x] [bp](https://github.com/ambroisie/tree-sitter-bp) (maintained by @ambroisie)
- [x] [brightscript](https://github.com/ajdelcimmuto/tree-sitter-brightscript) (maintained by @ajdelcimmuto)
- [x] [c](https://github.com/tree-sitter/tree-sitter-c) (maintained by @amaanq)
- [x] [c_sharp](https://github.com/tree-sitter/tree-sitter-c-sharp) (maintained by @amaanq)
- [x] [caddy](https://github.com/opa-oz/tree-sitter-caddy) (maintained by @opa-oz)
- [x] [cairo](https://github.com/amaanq/tree-sitter-cairo) (maintained by @amaanq)
- [x] [capnp](https://github.com/amaanq/tree-sitter-capnp) (maintained by @amaanq)
- [x] [chatito](https://github.com/ObserverOfTime/tree-sitter-chatito) (maintained by @ObserverOfTime)
- [x] [circom](https://github.com/Decurity/tree-sitter-circom) (maintained by @alexandr-martirosyan)
- [x] [clojure](https://github.com/sogaiu/tree-sitter-clojure) (maintained by @NoahTheDuke)
- [x] [cmake](https://github.com/uyha/tree-sitter-cmake) (maintained by @uyha)
- [x] [comment](https://github.com/stsewd/tree-sitter-comment) (maintained by @stsewd)
- [x] [commonlisp](https://github.com/theHamsta/tree-sitter-commonlisp) (maintained by @theHamsta)
- [x] [cooklang](https://github.com/addcninblue/tree-sitter-cooklang) (maintained by @addcninblue)
- [x] [corn](https://github.com/jakestanger/tree-sitter-corn) (maintained by @jakestanger)
- [x] [cpon](https://github.com/amaanq/tree-sitter-cpon) (maintained by @amaanq)
- [x] [cpp](https://github.com/tree-sitter/tree-sitter-cpp) (maintained by @theHamsta)
- [x] [css](https://github.com/tree-sitter/tree-sitter-css) (maintained by @TravonteD)
- [x] [csv](https://github.com/amaanq/tree-sitter-csv) (maintained by @amaanq)
- [x] [cuda](https://github.com/theHamsta/tree-sitter-cuda) (maintained by @theHamsta)
- [x] [cue](https://github.com/eonpatapon/tree-sitter-cue) (maintained by @amaanq)
- [x] [cylc](https://github.com/elliotfontaine/tree-sitter-cylc) (maintained by @elliotfontaine)
- [x] [d](https://github.com/gdamore/tree-sitter-d) (maintained by @amaanq)
- [x] [dart](https://github.com/UserNobody14/tree-sitter-dart) (maintained by @akinsho)
- [x] [desktop](https://github.com/ValdezFOmar/tree-sitter-desktop) (maintained by @ValdezFOmar)
- [x] [devicetree](https://github.com/joelspadin/tree-sitter-devicetree) (maintained by @jedrzejboczar)
- [x] [dhall](https://github.com/jbellerb/tree-sitter-dhall) (maintained by @amaanq)
- [x] [diff](https://github.com/the-mikedavis/tree-sitter-diff) (maintained by @gbprod)
- [x] [disassembly](https://github.com/ColinKennedy/tree-sitter-disassembly) (maintained by @ColinKennedy)
- [x] [djot](https://github.com/treeman/tree-sitter-djot) (maintained by @NoahTheDuke)
- [x] [dockerfile](https://github.com/camdencheek/tree-sitter-dockerfile) (maintained by @camdencheek)
- [x] [dot](https://github.com/rydesun/tree-sitter-dot) (maintained by @rydesun)
- [x] [doxygen](https://github.com/amaanq/tree-sitter-doxygen) (maintained by @amaanq)
- [x] [dtd](https://github.com/tree-sitter-grammars/tree-sitter-xml) (maintained by @ObserverOfTime)
- [x] [earthfile](https://github.com/glehmann/tree-sitter-earthfile) (maintained by @glehmann)
- [x] [ebnf](https://github.com/RubixDev/ebnf) (experimental, maintained by @RubixDev)
- [x] [editorconfig](https://github.com/ValdezFOmar/tree-sitter-editorconfig) (maintained by @ValdezFOmar)
- [x] [eds](https://github.com/uyha/tree-sitter-eds) (maintained by @uyha)
- [x] [eex](https://github.com/connorlay/tree-sitter-eex) (maintained by @connorlay)
- [x] [elixir](https://github.com/elixir-lang/tree-sitter-elixir) (maintained by @connorlay)
- [x] [elm](https://github.com/elm-tooling/tree-sitter-elm) (maintained by @zweimach)
- [x] [elsa](https://github.com/glapa-grossklag/tree-sitter-elsa) (maintained by @glapa-grossklag, @amaanq)
- [x] [elvish](https://github.com/elves/tree-sitter-elvish) (maintained by @elves)
- [ ] [embedded_template](https://github.com/tree-sitter/tree-sitter-embedded-template)
- [x] [enforce](https://github.com/simonvic/tree-sitter-enforce) (maintained by @simonvic)
- [x] [erlang](https://github.com/WhatsApp/tree-sitter-erlang) (maintained by @filmor)
- [x] [facility](https://github.com/FacilityApi/tree-sitter-facility) (maintained by @bryankenote)
- [x] [faust](https://github.com/khiner/tree-sitter-faust) (maintained by @khiner)
- [x] [fennel](https://github.com/alexmozaidze/tree-sitter-fennel) (maintained by @alexmozaidze)
- [x] [fidl](https://github.com/google/tree-sitter-fidl) (maintained by @chaopeng)
- [x] [firrtl](https://github.com/amaanq/tree-sitter-firrtl) (maintained by @amaanq)
- [x] [fish](https://github.com/ram02z/tree-sitter-fish) (maintained by @ram02z)
- [x] [foam](https://github.com/FoamScience/tree-sitter-foam) (experimental, maintained by @FoamScience)
- [x] [forth](https://github.com/AlexanderBrevig/tree-sitter-forth) (maintained by @amaanq)
- [x] [fortran](https://github.com/stadelmanma/tree-sitter-fortran) (maintained by @amaanq)
- [x] [fsh](https://github.com/mgramigna/tree-sitter-fsh) (maintained by @mgramigna)
- [x] [fsharp](https://github.com/ionide/tree-sitter-fsharp) (maintained by @nsidorenco)
- [x] [func](https://github.com/amaanq/tree-sitter-func) (maintained by @amaanq)
- [x] [fusion](https://gitlab.com/jirgn/tree-sitter-fusion.git) (maintained by @jirgn)
- [x] [GAP system](https://github.com/gap-system/tree-sitter-gap) (maintained by @reiniscirpons)
- [x] [GAP system test files](https://github.com/gap-system/tree-sitter-gaptst) (maintained by @reiniscirpons)
- [x] [Godot (gdscript)](https://github.com/PrestonKnopp/tree-sitter-gdscript) (maintained by @PrestonKnopp)
- [x] [gdshader](https://github.com/GodOfAvacyn/tree-sitter-gdshader) (maintained by @godofavacyn)
- [x] [git_config](https://github.com/the-mikedavis/tree-sitter-git-config) (maintained by @amaanq)
- [x] [git_rebase](https://github.com/the-mikedavis/tree-sitter-git-rebase) (maintained by @gbprod)
- [x] [gitattributes](https://github.com/ObserverOfTime/tree-sitter-gitattributes) (maintained by @ObserverOfTime)
- [x] [gitcommit](https://github.com/gbprod/tree-sitter-gitcommit) (maintained by @gbprod)
- [x] [gitignore](https://github.com/shunsambongi/tree-sitter-gitignore) (maintained by @theHamsta)
- [x] [gleam](https://github.com/gleam-lang/tree-sitter-gleam) (maintained by @amaanq)
- [x] [Glimmer and Ember](https://github.com/ember-tooling/tree-sitter-glimmer) (maintained by @NullVoxPopuli)
- [x] [glimmer_javascript](https://github.com/NullVoxPopuli/tree-sitter-glimmer-javascript) (maintained by @NullVoxPopuli)
- [x] [glimmer_typescript](https://github.com/NullVoxPopuli/tree-sitter-glimmer-typescript) (maintained by @NullVoxPopuli)
- [x] [glsl](https://github.com/theHamsta/tree-sitter-glsl) (maintained by @theHamsta)
- [x] [GN (Generate Ninja)](https://github.com/amaanq/tree-sitter-gn) (maintained by @amaanq)
- [x] [gnuplot](https://github.com/dpezto/tree-sitter-gnuplot) (maintained by @dpezto)
- [x] [go](https://github.com/tree-sitter/tree-sitter-go) (maintained by @theHamsta, @WinWisely268)
- [x] [goctl](https://github.com/chaozwn/tree-sitter-goctl) (maintained by @chaozwn)
- [x] [Godot Resources (gdresource)](https://github.com/PrestonKnopp/tree-sitter-godot-resource) (maintained by @pierpo)
- [x] [gomod](https://github.com/camdencheek/tree-sitter-go-mod) (maintained by @camdencheek)
- [x] [gosum](https://github.com/amaanq/tree-sitter-go-sum) (maintained by @amaanq)
- [x] [gotmpl](https://github.com/ngalaiko/tree-sitter-go-template) (maintained by @qvalentin)
- [x] [gowork](https://github.com/omertuc/tree-sitter-go-work) (maintained by @omertuc)
- [x] [gpg](https://github.com/ObserverOfTime/tree-sitter-gpg-config) (maintained by @ObserverOfTime)
- [x] [graphql](https://github.com/bkegley/tree-sitter-graphql) (maintained by @bkegley)
- [x] [gren](https://github.com/MaeBrooks/tree-sitter-gren) (maintained by @MaeBrooks)
- [x] [groovy](https://github.com/murtaza64/tree-sitter-groovy) (maintained by @murtaza64)
- [x] [gstlaunch](https://github.com/theHamsta/tree-sitter-gstlaunch) (maintained by @theHamsta)
- [ ] [hack](https://github.com/slackhq/tree-sitter-hack)
- [x] [hare](https://github.com/amaanq/tree-sitter-hare) (maintained by @amaanq)
- [x] [haskell](https://github.com/tree-sitter/tree-sitter-haskell) (maintained by @mrcjkb)
- [x] [haskell_persistent](https://github.com/MercuryTechnologies/tree-sitter-haskell-persistent) (maintained by @lykahb)
- [x] [hcl](https://github.com/MichaHoffmann/tree-sitter-hcl) (maintained by @MichaHoffmann)
- [x] [heex](https://github.com/connorlay/tree-sitter-heex) (maintained by @connorlay)
- [x] [helm](https://github.com/ngalaiko/tree-sitter-go-template) (maintained by @qvalentin)
- [x] [hjson](https://github.com/winston0410/tree-sitter-hjson) (maintained by @winston0410)
- [x] [hlsl](https://github.com/theHamsta/tree-sitter-hlsl) (maintained by @theHamsta)
- [x] [hlsplaylist](https://github.com/Freed-Wu/tree-sitter-hlsplaylist) (maintained by @Freed-Wu)
- [x] [hocon](https://github.com/antosha417/tree-sitter-hocon) (maintained by @antosha417)
- [x] [hoon](https://github.com/urbit-pilled/tree-sitter-hoon) (experimental, maintained by @urbit-pilled)
- [x] [html](https://github.com/tree-sitter/tree-sitter-html) (maintained by @TravonteD)
- [x] [htmldjango](https://github.com/interdependence/tree-sitter-htmldjango) (experimental, maintained by @ObserverOfTime)
- [x] [http](https://github.com/rest-nvim/tree-sitter-http) (maintained by @amaanq, @NTBBloodbath)
- [x] [hurl](https://github.com/pfeiferj/tree-sitter-hurl) (maintained by @pfeiferj)
- [x] [hyprlang](https://github.com/luckasRanarison/tree-sitter-hyprlang) (maintained by @luckasRanarison)
- [x] [idl](https://github.com/cathaysia/tree-sitter-idl) (maintained by @cathaysia)
- [x] [idris](https://github.com/kayhide/tree-sitter-idris) (maintained by @srghma)
- [x] [ini](https://github.com/justinmk/tree-sitter-ini) (experimental, maintained by @theHamsta)
- [x] [inko](https://github.com/inko-lang/tree-sitter-inko) (maintained by @yorickpeterse)
- [x] [ipkg](https://github.com/srghma/tree-sitter-ipkg) (maintained by @srghma)
- [x] [ispc](https://github.com/fab4100/tree-sitter-ispc) (maintained by @fab4100)
- [x] [janet_simple](https://github.com/sogaiu/tree-sitter-janet-simple) (maintained by @sogaiu)
- [x] [java](https://github.com/tree-sitter/tree-sitter-java) (maintained by @p00f)
- [x] [javadoc](https://github.com/rmuir/tree-sitter-javadoc) (maintained by @rmuir)
- [x] [javascript](https://github.com/tree-sitter/tree-sitter-javascript) (maintained by @steelsojka)
- [x] [jinja](https://github.com/cathaysia/tree-sitter-jinja) (maintained by @cathaysia)
- [x] [jinja_inline](https://github.com/cathaysia/tree-sitter-jinja) (maintained by @cathaysia)
- [x] [jq](https://github.com/flurie/tree-sitter-jq) (maintained by @ObserverOfTime)
- [x] [jsdoc](https://github.com/tree-sitter/tree-sitter-jsdoc) (maintained by @steelsojka)
- [x] [json](https://github.com/tree-sitter/tree-sitter-json) (maintained by @steelsojka)
- [x] [json5](https://github.com/Joakker/tree-sitter-json5) (maintained by @Joakker)
- [x] [JSON with comments](https://gitlab.com/WhyNotHugo/tree-sitter-jsonc.git) (maintained by @WhyNotHugo)
- [x] [jsonnet](https://github.com/sourcegraph/tree-sitter-jsonnet) (maintained by @nawordar)
- [x] [julia](https://github.com/tree-sitter/tree-sitter-julia) (maintained by @fredrikekre)
- [x] [just](https://github.com/IndianBoy42/tree-sitter-just) (maintained by @Hubro)
- [x] [kcl](https://github.com/kcl-lang/tree-sitter-kcl) (maintained by @bertbaron)
- [x] [kconfig](https://github.com/amaanq/tree-sitter-kconfig) (maintained by @amaanq)
- [x] [kdl](https://github.com/amaanq/tree-sitter-kdl) (maintained by @amaanq)
- [x] [kotlin](https://github.com/fwcd/tree-sitter-kotlin) (maintained by @SalBakraa)
- [x] [koto](https://github.com/koto-lang/tree-sitter-koto) (maintained by @irh)
- [x] [kusto](https://github.com/Willem-J-an/tree-sitter-kusto) (maintained by @Willem-J-an)
- [x] [lalrpop](https://github.com/traxys/tree-sitter-lalrpop) (maintained by @traxys)
- [x] [latex](https://github.com/latex-lsp/tree-sitter-latex) (maintained by @theHamsta, @clason)
- [x] [ledger](https://github.com/cbarrete/tree-sitter-ledger) (maintained by @cbarrete)
- [x] [leo](https://github.com/r001/tree-sitter-leo) (maintained by @r001)
- [x] [linkerscript](https://github.com/amaanq/tree-sitter-linkerscript) (maintained by @amaanq)
- [x] [liquid](https://github.com/hankthetank27/tree-sitter-liquid) (maintained by @hankthetank27)
- [x] [liquidsoap](https://github.com/savonet/tree-sitter-liquidsoap) (maintained by @toots)
- [x] [llvm](https://github.com/benwilliamgraham/tree-sitter-llvm) (maintained by @benwilliamgraham)
- [x] [lua](https://github.com/MunifTanjim/tree-sitter-lua) (maintained by @muniftanjim)
- [x] [luadoc](https://github.com/amaanq/tree-sitter-luadoc) (maintained by @amaanq)
- [x] [lua patterns](https://github.com/amaanq/tree-sitter-luap) (maintained by @amaanq)
- [x] [luau](https://github.com/amaanq/tree-sitter-luau) (maintained by @amaanq)
- [x] [m68k](https://github.com/grahambates/tree-sitter-m68k) (maintained by @grahambates)
- [x] [make](https://github.com/alemuller/tree-sitter-make) (maintained by @lewis6991)
- [x] [markdown (basic highlighting)](https://github.com/MDeiml/tree-sitter-markdown) (experimental, maintained by @MDeiml)
- [x] [markdown_inline (needed for full highlighting)](https://github.com/MDeiml/tree-sitter-markdown) (experimental, maintained by @MDeiml)
- [x] [matlab](https://github.com/acristoffers/tree-sitter-matlab) (maintained by @acristoffers)
- [x] [menhir](https://github.com/Kerl13/tree-sitter-menhir) (maintained by @Kerl13)
- [ ] [mermaid](https://github.com/monaqa/tree-sitter-mermaid) (experimental)
- [x] [meson](https://github.com/Decodetalkers/tree-sitter-meson) (maintained by @Decodetalkers)
- [x] [mlir](https://github.com/artagnon/tree-sitter-mlir) (experimental, maintained by @artagnon)
- [x] [muttrc](https://github.com/neomutt/tree-sitter-muttrc) (maintained by @Freed-Wu)
- [x] [nasm](https://github.com/naclsn/tree-sitter-nasm) (maintained by @ObserverOfTime)
- [x] [nginx](https://github.com/opa-oz/tree-sitter-nginx) (maintained by @opa-oz)
- [ ] [nickel](https://github.com/nickel-lang/tree-sitter-nickel)
- [x] [nim](https://github.com/alaviss/tree-sitter-nim) (maintained by @aMOPel)
- [x] [nim_format_string](https://github.com/aMOPel/tree-sitter-nim-format-string) (maintained by @aMOPel)
- [x] [ninja](https://github.com/alemuller/tree-sitter-ninja) (maintained by @alemuller)
- [x] [nix](https://github.com/cstrahan/tree-sitter-nix) (maintained by @leo60228)
- [x] [norg](https://github.com/nvim-neorg/tree-sitter-norg) (maintained by @JoeyGrajciar, @vhyrro)
- [x] [nqc](https://github.com/amaanq/tree-sitter-nqc) (maintained by @amaanq)
- [x] [nu](https://github.com/nushell/tree-sitter-nu) (maintained by @abhisheksingh0x558)
- [x] [objc](https://github.com/amaanq/tree-sitter-objc) (maintained by @amaanq)
- [x] [objdump](https://github.com/ColinKennedy/tree-sitter-objdump) (maintained by @ColinKennedy)
- [x] [ocaml](https://github.com/tree-sitter/tree-sitter-ocaml) (maintained by @undu)
- [x] [ocaml_interface](https://github.com/tree-sitter/tree-sitter-ocaml) (maintained by @undu)
- [x] [ocamllex](https://github.com/atom-ocaml/tree-sitter-ocamllex) (maintained by @undu)
- [x] [odin](https://github.com/amaanq/tree-sitter-odin) (maintained by @amaanq)
- [x] [pascal](https://github.com/Isopod/tree-sitter-pascal) (maintained by @Isopod)
- [x] [passwd](https://github.com/ath3/tree-sitter-passwd) (maintained by @amaanq)
- [x] [pem](https://github.com/ObserverOfTime/tree-sitter-pem) (maintained by @ObserverOfTime)
- [x] [perl](https://github.com/tree-sitter-perl/tree-sitter-perl) (maintained by @RabbiVeesh, @LeoNerd)
- [x] [php](https://github.com/tree-sitter/tree-sitter-php) (maintained by @tk-shirasaka, @calebdw)
- [x] [php_only](https://github.com/tree-sitter/tree-sitter-php) (maintained by @tk-shirasaka, @calebdw)
- [x] [phpdoc](https://github.com/claytonrcarter/tree-sitter-phpdoc) (experimental, maintained by @mikehaertl)
- [x] [pioasm](https://github.com/leo60228/tree-sitter-pioasm) (maintained by @leo60228)
- [x] [po](https://github.com/erasin/tree-sitter-po) (maintained by @amaanq)
- [x] [pod](https://github.com/tree-sitter-perl/tree-sitter-pod) (maintained by @RabbiVeesh, @LeoNerd)
- [x] [Path of Exile item filter](https://github.com/ObserverOfTime/tree-sitter-poe-filter) (experimental, maintained by @ObserverOfTime)
- [x] [pony](https://github.com/amaanq/tree-sitter-pony) (maintained by @amaanq, @mfelsche)
- [x] [powershell](https://github.com/airbus-cert/tree-sitter-powershell) (maintained by @L2jLiga)
- [x] [printf](https://github.com/ObserverOfTime/tree-sitter-printf) (maintained by @ObserverOfTime)
- [x] [prisma](https://github.com/victorhqc/tree-sitter-prisma) (maintained by @elianiva)
- [x] [problog](https://github.com/foxyseta/tree-sitter-prolog) (maintained by @foxyseta)
- [x] [prolog](https://github.com/foxyseta/tree-sitter-prolog) (maintained by @foxyseta)
- [x] [promql](https://github.com/MichaHoffmann/tree-sitter-promql) (maintained by @MichaHoffmann)
- [x] [properties](https://github.com/tree-sitter-grammars/tree-sitter-properties) (maintained by @ObserverOfTime)
- [x] [proto](https://github.com/treywood/tree-sitter-proto) (maintained by @treywood)
- [x] [prql](https://github.com/PRQL/tree-sitter-prql) (maintained by @matthias-Q)
- [x] [psv](https://github.com/amaanq/tree-sitter-csv) (maintained by @amaanq)
- [x] [pug](https://github.com/zealot128/tree-sitter-pug) (experimental, maintained by @zealot128)
- [x] [puppet](https://github.com/amaanq/tree-sitter-puppet) (maintained by @amaanq)
- [x] [purescript](https://github.com/postsolar/tree-sitter-purescript) (maintained by @postsolar)
- [x] [PyPA manifest](https://github.com/ObserverOfTime/tree-sitter-pymanifest) (maintained by @ObserverOfTime)
- [x] [python](https://github.com/tree-sitter/tree-sitter-python) (maintained by @stsewd, @theHamsta)
- [x] [ql](https://github.com/tree-sitter/tree-sitter-ql) (maintained by @pwntester)
- [x] [qmldir](https://github.com/Decodetalkers/tree-sitter-qmldir) (maintained by @amaanq)
- [x] [qmljs](https://github.com/yuja/tree-sitter-qmljs) (maintained by @Decodetalkers)
- [x] [Tree-Sitter query language](https://github.com/nvim-treesitter/tree-sitter-query) (maintained by @steelsojka)
- [x] [r](https://github.com/r-lib/tree-sitter-r) (maintained by @ribru17)
- [ ] [racket](https://github.com/6cdh/tree-sitter-racket)
- [x] [ralph](https://github.com/alephium/tree-sitter-ralph) (maintained by @tdroxler)
- [x] [rasi](https://github.com/Fymyte/tree-sitter-rasi) (maintained by @Fymyte)
- [x] [razor](https://github.com/tris203/tree-sitter-razor) (maintained by @tris203)
- [x] [rbs](https://github.com/joker1007/tree-sitter-rbs) (maintained by @joker1007)
- [x] [re2c](https://github.com/amaanq/tree-sitter-re2c) (maintained by @amaanq)
- [x] [readline](https://github.com/ribru17/tree-sitter-readline) (maintained by @ribru17)
- [x] [regex](https://github.com/tree-sitter/tree-sitter-regex) (maintained by @theHamsta)
- [x] [rego](https://github.com/FallenAngel97/tree-sitter-rego) (maintained by @FallenAngel97)
- [x] [pip requirements](https://github.com/ObserverOfTime/tree-sitter-requirements) (maintained by @ObserverOfTime)
- [x] [rescript](https://github.com/rescript-lang/tree-sitter-rescript) (maintained by @ribru17)
- [x] [rnoweb](https://github.com/bamonroe/tree-sitter-rnoweb) (maintained by @bamonroe)
- [x] [robot](https://github.com/Hubro/tree-sitter-robot) (maintained by @Hubro)
- [x] [robots](https://github.com/opa-oz/tree-sitter-robots-txt) (maintained by @opa-oz)
- [x] [roc](https://github.com/faldor20/tree-sitter-roc) (maintained by @nat-418)
- [x] [ron](https://github.com/amaanq/tree-sitter-ron) (maintained by @amaanq)
- [x] [rst](https://github.com/stsewd/tree-sitter-rst) (maintained by @stsewd)
- [x] [ruby](https://github.com/tree-sitter/tree-sitter-ruby) (maintained by @TravonteD)
- [x] [runescript](https://github.com/2004Scape/tree-sitter-runescript) (maintained by @2004Scape)
- [x] [rust](https://github.com/tree-sitter/tree-sitter-rust) (maintained by @amaanq)
- [x] [scala](https://github.com/tree-sitter/tree-sitter-scala) (maintained by @stevanmilic)
- [x] [scfg](https://github.com/rockorager/tree-sitter-scfg) (maintained by @WhyNotHugo)
- [ ] [scheme](https://github.com/6cdh/tree-sitter-scheme)
- [x] [scss](https://github.com/serenadeai/tree-sitter-scss) (maintained by @elianiva)
- [x] [sflog](https://github.com/aheber/tree-sitter-sfapex) (maintained by @aheber, @xixiaofinland)
- [x] [slang](https://github.com/theHamsta/tree-sitter-slang) (experimental, maintained by @theHamsta)
- [x] [slim](https://github.com/theoo/tree-sitter-slim) (maintained by @theoo)
- [x] [slint](https://github.com/slint-ui/tree-sitter-slint) (maintained by @hunger)
- [x] [smali](https://github.com/tree-sitter-grammars/tree-sitter-smali) (maintained by @amaanq)
- [x] [smithy](https://github.com/indoorvivants/tree-sitter-smithy) (maintained by @amaanq, @keynmol)
- [ ] [snakemake](https://github.com/osthomas/tree-sitter-snakemake) (experimental)
- [x] [solidity](https://github.com/JoranHonig/tree-sitter-solidity) (maintained by @amaanq)
- [x] [soql](https://github.com/aheber/tree-sitter-sfapex) (maintained by @aheber, @xixiaofinland)
- [x] [sosl](https://github.com/aheber/tree-sitter-sfapex) (maintained by @aheber, @xixiaofinland)
- [x] [sourcepawn](https://github.com/nilshelmig/tree-sitter-sourcepawn) (maintained by @Sarrus1)
- [x] [sparql](https://github.com/GordianDziwis/tree-sitter-sparql) (maintained by @GordianDziwis)
- [x] [sql](https://github.com/derekstride/tree-sitter-sql) (maintained by @derekstride)
- [x] [squirrel](https://github.com/amaanq/tree-sitter-squirrel) (maintained by @amaanq)
- [x] [ssh_config](https://github.com/ObserverOfTime/tree-sitter-ssh-config) (maintained by @ObserverOfTime)
- [x] [starlark](https://github.com/amaanq/tree-sitter-starlark) (maintained by @amaanq)
- [x] [strace](https://github.com/sigmaSd/tree-sitter-strace) (maintained by @amaanq)
- [x] [styled](https://github.com/mskelton/tree-sitter-styled) (maintained by @mskelton)
- [x] [supercollider](https://github.com/madskjeldgaard/tree-sitter-supercollider) (maintained by @madskjeldgaard)
- [x] [superhtml](https://github.com/kristoff-it/superhtml) (maintained by @rockorager)
- [x] [surface](https://github.com/connorlay/tree-sitter-surface) (maintained by @connorlay)
- [x] [svelte](https://github.com/tree-sitter-grammars/tree-sitter-svelte) (maintained by @amaanq)
- [x] [sway](https://github.com/FuelLabs/tree-sitter-sway.git) (maintained by @ribru17)
- [x] [swift](https://github.com/alex-pinkus/tree-sitter-swift) (maintained by @alex-pinkus)
- [x] [sxhkdrc](https://github.com/RaafatTurki/tree-sitter-sxhkdrc) (maintained by @RaafatTurki)
- [x] [systemtap](https://github.com/ok-ryoko/tree-sitter-systemtap) (maintained by @ok-ryoko)
- [x] [t32](https://gitlab.com/xasc/tree-sitter-t32.git) (maintained by @xasc)
- [x] [tablegen](https://github.com/amaanq/tree-sitter-tablegen) (maintained by @amaanq)
- [x] [tact](https://github.com/tact-lang/tree-sitter-tact) (maintained by @novusnota)
- [x] [tcl](https://github.com/tree-sitter-grammars/tree-sitter-tcl) (maintained by @lewis6991)
- [x] [teal](https://github.com/euclidianAce/tree-sitter-teal) (maintained by @euclidianAce)
- [x] [templ](https://github.com/vrischmann/tree-sitter-templ) (maintained by @vrischmann)
- [x] [tera](https://github.com/uncenter/tree-sitter-tera) (maintained by @uncenter)
- [x] [terraform](https://github.com/MichaHoffmann/tree-sitter-hcl) (maintained by @MichaHoffmann)
- [x] [textproto](https://github.com/PorterAtGoogle/tree-sitter-textproto) (maintained by @Porter)
- [x] [thrift](https://github.com/duskmoon314/tree-sitter-thrift) (maintained by @amaanq, @duskmoon314)
- [x] [tiger](https://github.com/ambroisie/tree-sitter-tiger) (maintained by @ambroisie)
- [x] [tlaplus](https://github.com/tlaplus-community/tree-sitter-tlaplus) (maintained by @ahelwer, @susliko)
- [x] [tmux](https://github.com/Freed-Wu/tree-sitter-tmux) (maintained by @Freed-Wu)
- [x] [todotxt](https://github.com/arnarg/tree-sitter-todotxt) (experimental, maintained by @arnarg)
- [x] [toml](https://github.com/tree-sitter-grammars/tree-sitter-toml) (maintained by @tk-shirasaka)
- [x] [tsv](https://github.com/amaanq/tree-sitter-csv) (maintained by @amaanq)
- [x] [tsx](https://github.com/tree-sitter/tree-sitter-typescript) (maintained by @steelsojka)
- [x] [turtle](https://github.com/GordianDziwis/tree-sitter-turtle) (maintained by @GordianDziwis)
- [x] [twig](https://github.com/gbprod/tree-sitter-twig) (maintained by @gbprod)
- [x] [typescript](https://github.com/tree-sitter/tree-sitter-typescript) (maintained by @steelsojka)
- [x] [typespec](https://github.com/happenslol/tree-sitter-typespec) (maintained by @happenslol)
- [x] [typoscript](https://github.com/Teddytrombone/tree-sitter-typoscript) (maintained by @Teddytrombone)
- [x] [typst](https://github.com/uben0/tree-sitter-typst) (maintained by @uben0, @RaafatTurki)
- [x] [udev](https://github.com/ObserverOfTime/tree-sitter-udev) (maintained by @ObserverOfTime)
- [x] [ungrammar](https://github.com/Philipp-M/tree-sitter-ungrammar) (maintained by @Philipp-M, @amaanq)
- [x] [unison](https://github.com/kylegoetz/tree-sitter-unison) (maintained by @tapegram)
- [x] [usd](https://github.com/ColinKennedy/tree-sitter-usd) (maintained by @ColinKennedy)
- [x] [uxn tal](https://github.com/amaanq/tree-sitter-uxntal) (maintained by @amaanq)
- [x] [v](https://github.com/vlang/v-analyzer) (maintained by @kkharji, @amaanq)
- [x] [vala](https://github.com/vala-lang/tree-sitter-vala) (maintained by @Prince781)
- [x] [vento](https://github.com/ventojs/tree-sitter-vento) (maintained by @wrapperup, @oscarotero)
- [x] [verilog](https://github.com/gmlarumbe/tree-sitter-systemverilog) (maintained by @zhangwwpeng)
- [x] [vhdl](https://github.com/jpt13653903/tree-sitter-vhdl) (maintained by @jpt13653903)
- [x] [vhs](https://github.com/charmbracelet/tree-sitter-vhs) (maintained by @caarlos0)
- [x] [vim](https://github.com/neovim/tree-sitter-vim) (maintained by @clason)
- [x] [vimdoc](https://github.com/neovim/tree-sitter-vimdoc) (maintained by @clason)
- [x] [vrl](https://github.com/belltoy/tree-sitter-vrl) (maintained by @belltoy)
- [x] [vue](https://github.com/tree-sitter-grammars/tree-sitter-vue) (maintained by @WhyNotHugo, @lucario387)
- [x] [wgsl](https://github.com/szebniok/tree-sitter-wgsl) (maintained by @szebniok)
- [x] [wgsl_bevy](https://github.com/theHamsta/tree-sitter-wgsl-bevy) (maintained by @theHamsta)
- [x] [wing](https://github.com/winglang/tree-sitter-wing) (maintained by @gshpychka, @MarkMcCulloh)
- [x] [wit](https://github.com/liamwh/tree-sitter-wit) (maintained by @liamwh)
- [x] [xcompose](https://github.com/ObserverOfTime/tree-sitter-xcompose) (maintained by @ObserverOfTime)
- [x] [xml](https://github.com/tree-sitter-grammars/tree-sitter-xml) (maintained by @ObserverOfTime)
- [x] [xresources](https://github.com/ValdezFOmar/tree-sitter-xresources) (maintained by @ValdezFOmar)
- [x] [yaml](https://github.com/tree-sitter-grammars/tree-sitter-yaml) (maintained by @amaanq)
- [x] [yang](https://github.com/Hubro/tree-sitter-yang) (maintained by @Hubro)
- [x] [yuck](https://github.com/Philipp-M/tree-sitter-yuck) (maintained by @Philipp-M, @amaanq)
- [x] [zathurarc](https://github.com/Freed-Wu/tree-sitter-zathurarc) (maintained by @Freed-Wu)
- [x] [zig](https://github.com/tree-sitter-grammars/tree-sitter-zig) (maintained by @amaanq)
- [x] [ziggy](https://github.com/kristoff-it/ziggy) (maintained by @rockorager)
- [x] [ziggy_schema](https://github.com/kristoff-it/ziggy) (maintained by @rockorager)
<!--parserinfo-->
## Highlighting
For related information on the supported languages, including related plugins, see [this wiki page](https://github.com/nvim-treesitter/nvim-treesitter/wiki/Supported-Languages-Information).
# Available modules
Modules provide the top-level features of `nvim-treesitter`.
The following is a list of modules included in `nvim-treesitter` and their configuration via `init.lua` (where multiple modules can be combined in a single call to `setup`).
Note that not all modules work for all languages (depending on the queries available for them).
Additional modules can be provided as [external plugins](https://github.com/nvim-treesitter/nvim-treesitter/wiki/Extra-modules-and-plugins).
#### Highlight
Consistent syntax highlighting.
Treesitter highlighting is provided by Neovim, see `:h treesitter-highlight`. To enable it for a filetype, put `vim.treesitter.start()` in a `ftplugin/<filetype>.lua` in your config directory, or place the following in your `init.lua`:
```lua
require'nvim-treesitter.configs'.setup {
highlight = {
enable = true,
-- Setting this to true will run `:h syntax` and tree-sitter at the same time.
-- Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
-- Using this option may slow down your editor, and you may see some duplicate highlights.
-- Instead of true it can also be a list of languages
additional_vim_regex_highlighting = false,
},
}
vim.api.nvim_create_autocmd('FileType', {
pattern = { '<filetype>' },
callback = function() vim.treesitter.start() end,
})
```
To customize the syntax highlighting of a capture, simply define or link a highlight group of the same name:
## Folds
Treesitter-based folding is provided by Neovim. To enable it, put the following in your `ftplugin` or `FileType` autocommand:
```lua
-- Highlight the @foo.bar capture group with the "Identifier" highlight group
vim.api.nvim_set_hl(0, "@foo.bar", { link = "Identifier" })
vim.wo[0][0].foldexpr = 'v:lua.vim.treesitter.foldexpr()'
vim.wo[0][0].foldmethod = 'expr'
```
For a language-specific highlight, append the name of the language:
## Indentation
Treesitter-based indentation is provided by this plugin but considered **experimental**. To enable it, put the following in your `ftplugin` or `FileType` autocommand:
```lua
-- Highlight @foo.bar as "Identifier" only in Lua files
vim.api.nvim_set_hl(0, "@foo.bar.lua", { link = "Identifier" })
vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
```
See `:h treesitter-highlight-groups` for details.
(Note the specific quotes used.)
#### Incremental selection
## Injections
Incremental selection based on the named nodes from the grammar.
Injections are used for multi-language documents, see `:h treesitter-language-injections`. No setup is needed.
```lua
require'nvim-treesitter.configs'.setup {
incremental_selection = {
enable = true,
keymaps = {
init_selection = "gnn", -- set to `false` to disable one of the mappings
node_incremental = "grn",
scope_incremental = "grc",
node_decremental = "grm",
},
},
}
```
## Locals
#### Indentation
Indentation based on treesitter for the `=` operator.
**NOTE: This is an experimental feature**.
```lua
require'nvim-treesitter.configs'.setup {
indent = {
enable = true
}
}
```
#### Folding
Tree-sitter based folding (implemented in Neovim itself, see `:h vim.treesitter.foldexpr()`). To enable it for the current window, set
```lua
vim.wo.foldmethod = 'expr'
vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()'
```
This will respect your `foldminlines` and `foldnestmax` settings.
These queries can be used to look up definitions and references to identifiers in a given scope. They are not used in this plugin and are provided for (limited) backward compatibility.
# Advanced setup
## Changing the parser install directory
If you want to install the parsers to a custom directory you can specify this
directory with `parser_install_dir` option in that is passed to `setup`.
`nvim-treesitter` will then install the parser files into this directory.
This directory must be writeable and must be explicitly prepended to the
`runtimepath`. For example:
```lua
-- It MUST be at the beginning of runtimepath. Otherwise the parsers from Neovim itself
-- is loaded that may not be compatible with the queries from the 'nvim-treesitter' plugin.
vim.opt.runtimepath:prepend("/some/path/to/store/parsers")
require'nvim-treesitter.configs'.setup {
parser_install_dir = "/some/path/to/store/parsers",
...
}
```
If this option is not included in the setup options, or is explicitly set to
`nil` then the default install directories will be used. If this value is set
the default directories will be ignored.
Bear in mind that any parser installed into a parser folder on the runtime path
will still be considered installed. (For example if
"~/.local/share/nvim/site/parser/c.so" exists then the "c" parser will be
considered installed, even though it is not in `parser_install_dir`)
The default paths are:
1. first the package folder. Where `nvim-treesitter` is installed.
2. second the site directory. This is the "site" subdirectory of `stdpath("data")`.
## Adding parsers
## Adding custom languages
If you have a parser that is not on the list of supported languages (either as a repository on Github or in a local directory), you can add it manually for use by `nvim-treesitter` as follows:
1. Clone the repository or [create a new project](https://tree-sitter.github.io/tree-sitter/creating-parsers#project-setup) in, say, `~/projects/tree-sitter-zimbu`. Make sure that the `tree-sitter-cli` executable is installed and in your path; see <https://tree-sitter.github.io/tree-sitter/creating-parsers#installation> for installation instructions.
2. Run `tree-sitter generate` in this directory (followed by `tree-sitter test` for good measure).
3. Add the following snippet to your `init.lua`:
1. Add the following snippet in a `User TSUpdate` autocommand:
```lua
local parser_config = require "nvim-treesitter.parsers".get_parser_configs()
parser_config.zimbu = {
install_info = {
url = "~/projects/tree-sitter-zimbu", -- local path or git repo
files = {"src/parser.c"}, -- note that some parsers also require src/scanner.c or src/scanner.cc
-- optional entries:
branch = "main", -- default branch in case of git repo if different from master
generate_requires_npm = false, -- if stand-alone parser without npm dependencies
requires_generate_from_grammar = false, -- if folder contains pre-generated src/parser.c
},
filetype = "zu", -- if filetype does not match the parser name
}
vim.api.nvim_create_autocmd('User', { pattern = 'TSUpdate',
callback = function()
require('nvim-treesitter.parsers').zimbu = {
install_info = {
url = 'https://github.com/zimbulang/tree-sitter-zimbu',
revision = <sha>, -- commit hash for revision to check out; HEAD if missing
-- optional entries:
branch = 'develop', -- only needed if different from default branch
location = 'parser', -- only needed if the parser is in subdirectory of a "monorepo"
generate = true, -- only needed if repo does not contain pre-generated `src/parser.c`
generate_from_json = false, -- only needed if repo does not contain `src/grammar.json` either
queries = 'queries/neovim', -- also install queries from given directory
},
}
end})
```
If you wish to set a specific parser for a filetype, you should use `vim.treesitter.language.register()`:
Alternatively, if you have a local checkout, you can instead use
```lua
vim.treesitter.language.register('python', 'someft') -- the someft filetype will use the python parser and queries.
install_info = {
path = '~/parsers/tree-sitter-zimbu',
-- optional entries
location = 'parser',
generate = true,
generate_from_json = false,
queries = 'queries/neovim', -- symlink queries from given directory
},
```
This will always use the state of the directory as-is (i.e., `branch` and `revision` will be ignored).
2. If the parser name differs from the filetype(s) used by Neovim, you need to register the parser via
```lua
vim.treesitter.language.register('zimbu', { 'zu' })
```
Note this requires Nvim v0.9.
4. Start `nvim` and `:TSInstall zimbu`.
You can also skip step 2 and use `:TSInstallFromGrammar zimbu` to install directly from a `grammar.js` in the top-level directory specified by `url`.
Once the parser is installed, you can update it (from the latest revision of the `main` branch if `url` is a Github repository) with `:TSUpdate zimbu`.
Note that neither `:TSInstall` nor `:TSInstallFromGrammar` copy query files from the grammar repository.
If you want your installed grammar to be useful, you must manually [add query files](#adding-queries) to your local nvim-treesitter installation.
Note also that module functionality is only triggered if your language's filetype is correctly identified.
If Neovim does not detect your language's filetype by default, you can use [Neovim's `vim.filetype.add()`](<https://neovim.io/doc/user/lua.html#vim.filetype.add()>) to add a custom detection rule.
If you use a git repository for your parser and want to use a specific version, you can set the `revision` key
in the `install_info` table for you parser config.
3. Start `nvim` and `:TSInstall zimbu`.
>[!IMPORTANT]
> If the parser requires an external scanner, this must be written in C.
### Modifying parsers
You can use the same approach for overriding parser information. E.g., if you always want to generate the `lua` parser from grammar, add
```lua
vim.api.nvim_create_autocmd('User', { pattern = 'TSUpdate',
callback = function()
require('nvim-treesitter.parsers').lua.install_info.generate = true
end})
```
## Adding queries
Queries are what `nvim-treesitter` uses to extract information from the syntax tree;
they are located in the `queries/{language}/*` runtime directories (see `:h rtp`),
like the `queries` folder of this plugin, e.g. `queries/{language}/{locals,highlights,textobjects}.scm`.
Other modules may require additional queries such as `folding.scm`. You can find a
list of all supported capture names in [CONTRIBUTING.md](https://github.com/nvim-treesitter/nvim-treesitter/blob/master/CONTRIBUTING.md#parser-configurations).
The first query file on `runtimepath` will be used (see `:h treesitter-query`).
If you want to make a query on the user config extend other queries instead of
replacing them, see `:h treesitter-query-modeline-extends`.
If you want to completely override a query, you can use `:h vim.treesitter.query.set()`.
For example, to override the `injections` queries from `c` with your own:
```lua
vim.treesitter.query.set("c", "injections", "(comment) @comment")
```
Note: when using `query.set()`, all queries in the runtime directories will be ignored.
## Adding modules
If you wish you write your own module, you need to support
- tree-sitter language detection support;
- attaching and detaching to buffers;
- all nvim-treesitter commands.
At the top level, you can use the `define_modules` function to define one or more modules or module groups:
```lua
require'nvim-treesitter'.define_modules {
my_cool_plugin = {
attach = function(bufnr, lang)
-- Do cool stuff here
end,
detach = function(bufnr)
-- Undo cool stuff here
end,
is_supported = function(lang)
-- Check if the language is supported
end
}
}
```
with the following properties:
- `module_path` specifies a require path (string) that exports a module with an `attach` and `detach` function. This is not required if the functions are on this definition.
- `enable` determines if the module is enabled by default. This is usually overridden by the user.
- `disable` takes a list of languages that this module is disabled for. This is usually overridden by the user.
- `is_supported` takes a function that takes a language and determines if this module supports that language.
- `attach` takes a function that attaches to a buffer. This is required if `module_path` is not provided.
- `detach` takes a function that detaches from a buffer. This is required if `module_path` is not provided.
# Extra features
### Statusline indicator
```vim
echo nvim_treesitter#statusline(90) " 90 can be any length
module->expression_statement->call->identifier
```
### Utilities
You can get some utility functions with
```lua
local ts_utils = require 'nvim-treesitter.ts_utils'
```
Check [`:h nvim-treesitter-utils`](doc/nvim-treesitter.txt) for more information.
# Troubleshooting
Before doing anything, make sure you have the latest version of this plugin and run `:checkhealth nvim-treesitter`.
It can also help to update the parsers via `:TSUpdate`.
#### Feature `X` does not work for `{language}`...
First, check the `health#nvim_treesitter#check` and the `health#treesitter#check` sections of `:checkhealth` for any warning.
If there is one, it's highly likely that this is the cause of the problem.
Next check the `## Parser/Features` subsection of the `health#nvim_treesitter#check` section of `:checkhealth` to ensure the desired module is enabled for your language.
If not, you might be missing query files; see [Adding queries](#adding-queries).
Finally, ensure Neovim is correctly identifying your language's filetype using the `:echo &filetype` command while one of your language's files is open in Neovim.
If not, add a short Vimscript file to nvim-treesitter's `ftdetect` runtime directory following [Neovim's documentation](https://neovim.io/doc/user/filetype.html#new-filetype) on filetype detection.
You can also quickly & temporarily set the filetype for a single buffer with the `:set filetype=langname` command to test whether it fixes the problem.
If everything is okay, then it might be an actual error.
In that case, feel free to [open an issue here](https://github.com/nvim-treesitter/nvim-treesitter/issues/new/choose).
#### I get `module 'vim.treesitter.query' not found`
Make sure you have the latest version of Neovim.
#### I get `Error detected while processing .../plugin/nvim-treesitter.vim` every time I open Neovim
This is probably due to a change in a parser's grammar or its queries.
Try updating the parser that you suspect has changed (`:TSUpdate {language}`) or all of them (`:TSUpdate`).
If the error persists after updating all parsers,
please [open an issue](https://github.com/nvim-treesitter/nvim-treesitter/issues/new/choose).
#### I get `query error: invalid node type at position`
This could be due a query file outside this plugin using outdated nodes,
or due to an outdated parser.
- Make sure you have the parsers up to date with `:TSUpdate`
- Make sure you don't have more than one `parser` runtime directory.
You can execute this command `:echo nvim_get_runtime_file('parser', v:true)` to find all runtime directories.
If you get more than one path, remove the ones that are outside this plugin (`nvim-treesitter` directory),
so the correct version of the parser is used.
#### I experience weird highlighting issues similar to [#78](https://github.com/nvim-treesitter/nvim-treesitter/issues/78)
This is a well known issue, which arises when the tree and the buffer have gotten out of sync.
As this is an upstream issue, we don't have any definite fix.
To get around this, you can force reparsing the buffer with
```vim
:write | edit | TSBufEnable highlight
```
This will save, restore and enable highlighting for the current buffer.
#### I experience bugs when using `nvim-treesitter`'s `foldexpr` similar to [#194](https://github.com/nvim-treesitter/nvim-treesitter/issues/194)
This might happen, and is known to happen, with `vim-clap`.
To avoid these kind of errors, please use `setlocal` instead of `set` for the respective filetypes.
#### I run into errors like `module 'nvim-treesitter.configs' not found` at startup
This is because of `rtp` management in `nvim`, adding `packadd
nvim-treesitter` should fix the issue.
#### I want to use Git instead of curl for downloading the parsers
In your Lua config:
```lua
require("nvim-treesitter.install").prefer_git = true
```
#### I want to use a HTTP proxy for downloading the parsers
You can either configure curl to use additional CLI arguments in your Lua config:
```lua
require("nvim-treesitter.install").command_extra_args = {
curl = { "--proxy", "<proxy url>" },
}
```
or you can configure git via `.gitconfig` and use git instead of curl
```lua
require("nvim-treesitter.install").prefer_git = true
```
#### I want to use a mirror instead of "https://github.com/"
In your Lua config:
```lua
for _, config in pairs(require("nvim-treesitter.parsers").get_parser_configs()) do
config.install_info.url = config.install_info.url:gsub("https://github.com/", "something else")
end
require'nvim-treesitter.configs'.setup {
--
--
}
```
#### Using an existing parser for another filetype
For example, to use the `bash` tree-sitter to highlight file with
`filetype=apkbuild`, use:
```lua
vim.treesitter.language.register("bash", "apkbuild")
```
The `bash` tree-sitter must be installed following the usual procedure [as
described above](#language-parsers).
Queries can be placed anywhere in your `runtimepath` under `queries/<language>`, with earlier directories taking precedence unless the queries are marked with `; extends`; see [`:h treesitter-query-modelines`](https://neovim.io/doc/user/treesitter.html#treesitter-query-modeline).

365
SUPPORTED_LANGUAGES.md generated Normal file
View file

@ -0,0 +1,365 @@
# Supported languages
The following is a list of languages for which a parser can be installed through `:TSInstall`.
Legend:
- **Tier:** _stable_ (updates follow semver releases), _unstable_ (updates follow HEAD), _unmaintained_ (no automatic updates), or _unsupported_ (known to be broken, cannot be installed)
- **Queries** available for **H**ighlights, **F**olds, **I**ndents, In**J**ections, **L**ocals
- **Maintainer** of queries in nvim-treesitter (may be different from parser maintainer!)
<!--This section of the README is automatically updated by a CI job-->
<!--parserinfo-->
Language | Tier | Queries | Maintainer
-------- |:----:|:-------:| ----------
[ada](https://github.com/briot/tree-sitter-ada) | unstable | `HF JL` | @briot
[agda](https://github.com/tree-sitter/tree-sitter-agda) | unstable | `HF J ` | @Decodetalkers
[angular](https://github.com/dlvandenberg/tree-sitter-angular) | unstable | `HFIJL` | @dlvandenberg
[apex](https://github.com/aheber/tree-sitter-sfapex) | unstable | `HF JL` | @aheber, @xixiafinland
[arduino](https://github.com/tree-sitter-grammars/tree-sitter-arduino) | unstable | `HFIJL` | @ObserverOfTime
[asm](https://github.com/RubixDev/tree-sitter-asm) | unstable | `H  J ` | @RubixDev
[astro](https://github.com/virchau13/tree-sitter-astro) | unstable | `HFIJL` | @virchau13
[authzed](https://github.com/mleonidas/tree-sitter-authzed) | unstable | `H  J ` | @mattpolzin
[awk](https://github.com/Beaglefoot/tree-sitter-awk) | unstable | `H  J ` |
[bash](https://github.com/tree-sitter/tree-sitter-bash) | unstable | `HFIJL` | @TravonteD
[bass](https://github.com/vito/tree-sitter-bass) | unstable | `HFIJL` | @amaanq
[beancount](https://github.com/polarmutex/tree-sitter-beancount) | unstable | `HF J ` | @polarmutex
[bibtex](https://github.com/latex-lsp/tree-sitter-bibtex) | unstable | `HFIJ ` | @theHamsta, @clason
[bicep](https://github.com/tree-sitter-grammars/tree-sitter-bicep) | unstable | `HFIJL` | @amaanq
[bitbake](https://github.com/tree-sitter-grammars/tree-sitter-bitbake) | unstable | `HFIJL` | @amaanq
[blade](https://github.com/EmranMR/tree-sitter-blade) | unstable | `HFIJ ` | @calebdw
[bp](https://github.com/ambroisie/tree-sitter-bp)[^bp] | unstable | `HFIJL` | @ambroisie
[bpftrace](https://github.com/sgruszka/tree-sitter-bpftrace) | unstable | `H  J ` | @sgruszka
[brightscript](https://github.com/ajdelcimmuto/tree-sitter-brightscript) | unstable | `HFIJ ` | @ajdelcimmuto
[c](https://github.com/tree-sitter/tree-sitter-c) | unstable | `HFIJL` | @amaanq
[c3](https://github.com/c3lang/tree-sitter-c3) | unstable | `HFIJ ` | @cbuttner
[c_sharp](https://github.com/tree-sitter/tree-sitter-c-sharp) | unstable | `HF JL` | @amaanq
[caddy](https://github.com/opa-oz/tree-sitter-caddy) | unmaintained | `HFIJ ` |
[cairo](https://github.com/tree-sitter-grammars/tree-sitter-cairo) | unstable | `HFIJL` | @amaanq
[capnp](https://github.com/tree-sitter-grammars/tree-sitter-capnp) | unstable | `HFIJL` | @amaanq
[chatito](https://github.com/tree-sitter-grammars/tree-sitter-chatito) | unstable | `HFIJL` | @ObserverOfTime
[circom](https://github.com/Decurity/tree-sitter-circom) | unstable | `HF JL` | @alexandr-martirosyan
[clojure](https://github.com/sogaiu/tree-sitter-clojure) | unstable | `HF JL` | @NoahTheDuke
[cmake](https://github.com/uyha/tree-sitter-cmake) | unstable | `HFIJ ` | @uyha
[comment](https://github.com/stsewd/tree-sitter-comment) | unstable | `H    ` | @stsewd
[commonlisp](https://github.com/tree-sitter-grammars/tree-sitter-commonlisp) | unstable | `HF JL` | @theHamsta
[cooklang](https://github.com/addcninblue/tree-sitter-cooklang) | unstable | `H  J ` | @addcninblue
[corn](https://github.com/jakestanger/tree-sitter-corn) | unstable | `HFIJL` | @jakestanger
[cpon](https://github.com/tree-sitter-grammars/tree-sitter-cpon) | unstable | `HFIJL` | @amaanq
[cpp](https://github.com/tree-sitter/tree-sitter-cpp) | unstable | `HFIJL` | @theHamsta
[css](https://github.com/tree-sitter/tree-sitter-css) | unstable | `HFIJ ` | @TravonteD
[csv](https://github.com/tree-sitter-grammars/tree-sitter-csv) | unstable | `H    ` | @amaanq
[cuda](https://github.com/tree-sitter-grammars/tree-sitter-cuda) | unstable | `HFIJL` | @theHamsta
[cue](https://github.com/eonpatapon/tree-sitter-cue) | unstable | `HFIJL` | @amaanq
[cylc](https://github.com/elliotfontaine/tree-sitter-cylc) | unstable | `HFIJ ` | @elliotfontaine
[d](https://github.com/gdamore/tree-sitter-d) | unstable | `HFIJL` | @amaanq
[dart](https://github.com/UserNobody14/tree-sitter-dart) | unstable | `HFIJL` | @akinsho
[desktop](https://github.com/ValdezFOmar/tree-sitter-desktop) | stable | `HF J ` | @ValdezFOmar
[devicetree](https://github.com/joelspadin/tree-sitter-devicetree) | unstable | `HFIJL` | @jedrzejboczar
[dhall](https://github.com/jbellerb/tree-sitter-dhall) | unstable | `HF J ` | @amaanq
[diff](https://github.com/tree-sitter-grammars/tree-sitter-diff) | unstable | `HF J ` | @gbprod
[disassembly](https://github.com/ColinKennedy/tree-sitter-disassembly) | unstable | `H  J ` | @ColinKennedy
[djot](https://github.com/treeman/tree-sitter-djot) | unstable | `HFIJL` | @NoahTheDuke
[dockerfile](https://github.com/camdencheek/tree-sitter-dockerfile) | unstable | `H  J ` | @camdencheek
[dot](https://github.com/rydesun/tree-sitter-dot) | unstable | `HFIJ ` | @rydesun
[doxygen](https://github.com/tree-sitter-grammars/tree-sitter-doxygen) | unstable | `H IJ ` | @amaanq
[dtd](https://github.com/tree-sitter-grammars/tree-sitter-xml) | unstable | `HF JL` | @ObserverOfTime
[earthfile](https://github.com/glehmann/tree-sitter-earthfile) | unstable | `H  J ` | @glehmann
[ebnf](https://github.com/RubixDev/ebnf) | unstable | `H  J ` | @RubixDev
ecma (queries only)[^ecma] | unstable | `HFIJL` | @steelsojka
[editorconfig](https://github.com/ValdezFOmar/tree-sitter-editorconfig) | stable | `HF J ` | @ValdezFOmar
[eds](https://github.com/uyha/tree-sitter-eds) | unstable | `HF   ` | @uyha
[eex](https://github.com/connorlay/tree-sitter-eex) | unstable | `H  J ` | @connorlay
[elixir](https://github.com/elixir-lang/tree-sitter-elixir) | unstable | `HFIJL` | @connorlay
[elm](https://github.com/elm-tooling/tree-sitter-elm) | unstable | `HF J ` | @zweimach
[elsa](https://github.com/glapa-grossklag/tree-sitter-elsa) | unstable | `HFIJL` | @glapa-grossklag, @amaanq
[elvish](https://github.com/elves/tree-sitter-elvish) | unstable | `H  J ` | @elves
[embedded_template](https://github.com/tree-sitter/tree-sitter-embedded-template) | unstable | `H  J ` |
[enforce](https://github.com/simonvic/tree-sitter-enforce) | unstable | `HFIJL` | @simonvic
[erlang](https://github.com/WhatsApp/tree-sitter-erlang) | unstable | `HF J ` | @filmor
[facility](https://github.com/FacilityApi/tree-sitter-facility) | unstable | `HFIJ ` | @bryankenote
[faust](https://github.com/khiner/tree-sitter-faust) | unstable | `H  J ` | @khiner
[fennel](https://github.com/alexmozaidze/tree-sitter-fennel) | unstable | `HF JL` | @alexmozaidze
[fidl](https://github.com/google/tree-sitter-fidl) | unstable | `HF J ` | @chaopeng
[firrtl](https://github.com/tree-sitter-grammars/tree-sitter-firrtl) | unstable | `HFIJL` | @amaanq
[fish](https://github.com/ram02z/tree-sitter-fish) | unstable | `HFIJL` | @ram02z
[foam](https://github.com/FoamScience/tree-sitter-foam) | unstable | `HFIJL` | @FoamScience
[forth](https://github.com/AlexanderBrevig/tree-sitter-forth) | unstable | `HFIJL` | @amaanq
[fortran](https://github.com/stadelmanma/tree-sitter-fortran) | unstable | `HFIJ ` | @amaanq
[fsh](https://github.com/mgramigna/tree-sitter-fsh) | unstable | `H  J ` | @mgramigna
[fsharp](https://github.com/ionide/tree-sitter-fsharp) | unstable | `H  J ` | @nsidorenco
[func](https://github.com/tree-sitter-grammars/tree-sitter-func) | unstable | `H  J ` | @amaanq
[gap](https://github.com/gap-system/tree-sitter-gap)[^gap] | unstable | `HF JL` | @reiniscirpons
[gaptst](https://github.com/gap-system/tree-sitter-gaptst)[^gaptst] | unstable | `HF J ` | @reiniscirpons
[gdscript](https://github.com/PrestonKnopp/tree-sitter-gdscript)[^gdscript] | unmaintained | `HFIJL` |
[gdshader](https://github.com/airblast-dev/tree-sitter-gdshader) | unstable | `H  J ` | @airblast-dev
[git_config](https://github.com/the-mikedavis/tree-sitter-git-config) | unstable | `HF J ` | @amaanq
[git_rebase](https://github.com/the-mikedavis/tree-sitter-git-rebase) | unstable | `H  J ` | @gbprod
[gitattributes](https://github.com/tree-sitter-grammars/tree-sitter-gitattributes) | unstable | `H  JL` | @ObserverOfTime
[gitcommit](https://github.com/gbprod/tree-sitter-gitcommit) | unstable | `H  J ` | @gbprod
[gitignore](https://github.com/shunsambongi/tree-sitter-gitignore) | unstable | `H  J ` | @theHamsta
[gleam](https://github.com/gleam-lang/tree-sitter-gleam) | unstable | `HFIJL` | @amaanq
[glimmer](https://github.com/ember-tooling/tree-sitter-glimmer)[^glimmer] | unstable | `HFIJL` | @NullVoxPopuli
[glimmer_javascript](https://github.com/NullVoxPopuli/tree-sitter-glimmer-javascript) | unstable | `HFIJL` | @NullVoxPopuli
[glimmer_typescript](https://github.com/NullVoxPopuli/tree-sitter-glimmer-typescript) | unstable | `HFIJ ` | @NullVoxPopuli
[glsl](https://github.com/tree-sitter-grammars/tree-sitter-glsl) | unstable | `HFIJL` | @theHamsta
[gn](https://github.com/tree-sitter-grammars/tree-sitter-gn) | unstable | `HFIJL` | @amaanq
[gnuplot](https://github.com/dpezto/tree-sitter-gnuplot) | unstable | `H  J ` | @dpezto
[go](https://github.com/tree-sitter/tree-sitter-go) | unstable | `HFIJL` | @theHamsta, @WinWisely268
[goctl](https://github.com/chaozwn/tree-sitter-goctl) | unstable | `HFIJ ` | @chaozwn
[godot_resource](https://github.com/PrestonKnopp/tree-sitter-godot-resource)[^godot_resource] | unstable | `HF JL` | @pierpo
[gomod](https://github.com/camdencheek/tree-sitter-go-mod) | unstable | `H  J ` | @camdencheek
[gosum](https://github.com/tree-sitter-grammars/tree-sitter-go-sum) | unstable | `H    ` | @amaanq
[gotmpl](https://github.com/ngalaiko/tree-sitter-go-template) | unstable | `HF JL` | @qvalentin
[gowork](https://github.com/omertuc/tree-sitter-go-work) | unstable | `H  J ` | @omertuc
[gpg](https://github.com/tree-sitter-grammars/tree-sitter-gpg-config) | unstable | `H  J ` | @ObserverOfTime
[graphql](https://github.com/bkegley/tree-sitter-graphql) | unstable | `H IJ ` | @bkegley
[gren](https://github.com/MaeBrooks/tree-sitter-gren) | unstable | `H  J ` | @MaeBrooks
[groovy](https://github.com/murtaza64/tree-sitter-groovy) | unstable | `HFIJL` | @murtaza64
[groq](https://github.com/ajrussellaudio/tree-sitter-groq) | unstable | `HFIJ ` | @ajrussellaudio
[gstlaunch](https://github.com/tree-sitter-grammars/tree-sitter-gstlaunch) | unstable | `H    ` | @theHamsta
[hack](https://github.com/slackhq/tree-sitter-hack) | unstable | `H  J ` |
[hare](https://github.com/tree-sitter-grammars/tree-sitter-hare) | unstable | `HFIJL` | @amaanq
[haskell](https://github.com/tree-sitter-grammars/tree-sitter-haskell) | unstable | `HF JL` | @mrcjkb
[haskell_persistent](https://github.com/MercuryTechnologies/tree-sitter-haskell-persistent) | unstable | `HF   ` | @lykahb
[hcl](https://github.com/tree-sitter-grammars/tree-sitter-hcl) | unstable | `HFIJ ` | @MichaHoffmann
[heex](https://github.com/connorlay/tree-sitter-heex) | unstable | `HFIJL` | @connorlay
[helm](https://github.com/ngalaiko/tree-sitter-go-template) | unstable | `HF JL` | @qvalentin
[hjson](https://github.com/winston0410/tree-sitter-hjson) | unstable | `HFIJL` | @winston0410
[hlsl](https://github.com/tree-sitter-grammars/tree-sitter-hlsl) | unstable | `HFIJL` | @theHamsta
[hlsplaylist](https://github.com/Freed-Wu/tree-sitter-hlsplaylist) | unstable | `H  J ` | @Freed-Wu
[hocon](https://github.com/antosha417/tree-sitter-hocon) | unstable | `HF J ` | @antosha417
[hoon](https://github.com/urbit-pilled/tree-sitter-hoon) | unstable | `HF JL` | @urbit-pilled
[html](https://github.com/tree-sitter/tree-sitter-html) | unstable | `HFIJL` | @TravonteD
html_tags (queries only)[^html_tags] | unstable | `H IJ ` | @TravonteD
[htmldjango](https://github.com/interdependence/tree-sitter-htmldjango) | unstable | `HFIJ ` | @ObserverOfTime
[http](https://github.com/rest-nvim/tree-sitter-http) | unstable | `HF J ` | @amaanq, @NTBBloodbath
[hurl](https://github.com/pfeiferj/tree-sitter-hurl) | unstable | `HFIJ ` | @pfeiferj
[hyprlang](https://github.com/tree-sitter-grammars/tree-sitter-hyprlang) | unstable | `HFIJ ` | @luckasRanarison
[idl](https://github.com/cathaysia/tree-sitter-idl) | unstable | `H IJ ` | @cathaysia
[idris](https://github.com/kayhide/tree-sitter-idris) | unstable | `HF JL` |
[ini](https://github.com/justinmk/tree-sitter-ini) | unstable | `HF J ` | @theHamsta
[inko](https://github.com/inko-lang/tree-sitter-inko) | stable | `HFIJL` | @yorickpeterse
[ispc](https://github.com/tree-sitter-grammars/tree-sitter-ispc) | unstable | `HFIJL` | @fab4100
[janet_simple](https://github.com/sogaiu/tree-sitter-janet-simple) | unstable | `HF JL` | @sogaiu
[java](https://github.com/tree-sitter/tree-sitter-java) | unstable | `HFIJL` | @p00f
[javadoc](https://github.com/rmuir/tree-sitter-javadoc) | unstable | `H IJ ` | @rmuir
[javascript](https://github.com/tree-sitter/tree-sitter-javascript) | unstable | `HFIJL` | @steelsojka
[jinja](https://github.com/cathaysia/tree-sitter-jinja)[^jinja] | unstable | `H  J ` | @cathaysia
[jinja_inline](https://github.com/cathaysia/tree-sitter-jinja)[^jinja_inline] | unstable | `H  J ` | @cathaysia
[jjdescription](https://github.com/ribru17/tree-sitter-jjdescription) | stable | `H  J ` | @ribru17
[jq](https://github.com/flurie/tree-sitter-jq) | unstable | `H  JL` | @ObserverOfTime
[jsdoc](https://github.com/tree-sitter/tree-sitter-jsdoc) | unstable | `H    ` | @steelsojka
[json](https://github.com/tree-sitter/tree-sitter-json) | unstable | `HFIJL` | @steelsojka
[json5](https://github.com/Joakker/tree-sitter-json5) | unstable | `H  J ` | @Joakker
[jsonnet](https://github.com/sourcegraph/tree-sitter-jsonnet) | unstable | `HF JL` | @nawordar
jsx (queries only)[^jsx] | unstable | `HFIJ ` | @steelsojka
[julia](https://github.com/tree-sitter-grammars/tree-sitter-julia) | unstable | `HFIJL` | @clason
[just](https://github.com/IndianBoy42/tree-sitter-just) | unstable | `HFIJL` | @Hubro
[kcl](https://github.com/kcl-lang/tree-sitter-kcl) | unstable | `HF J ` | @bertbaron
[kconfig](https://github.com/tree-sitter-grammars/tree-sitter-kconfig) | unstable | `HFIJL` | @amaanq
[kdl](https://github.com/tree-sitter-grammars/tree-sitter-kdl) | unstable | `HFIJL` | @amaanq
[kitty](https://github.com/OXY2DEV/tree-sitter-kitty) | unstable | `H  J ` | @OXY2DEV
[kos](https://github.com/kos-lang/tree-sitter-kos) | unstable | `HF JL` | @cdragan
[kotlin](https://github.com/fwcd/tree-sitter-kotlin) | unstable | `HF JL` |
[koto](https://github.com/koto-lang/tree-sitter-koto) | unstable | `HF JL` | @irh
[kusto](https://github.com/Willem-J-an/tree-sitter-kusto) | unstable | `H  J ` | @Willem-J-an
[lalrpop](https://github.com/traxys/tree-sitter-lalrpop) | unstable | `HF JL` | @traxys
[latex](https://github.com/latex-lsp/tree-sitter-latex) | unstable | `HF J ` | @theHamsta, @clason
[ledger](https://github.com/cbarrete/tree-sitter-ledger) | unstable | `HFIJ ` | @cbarrete
[leo](https://github.com/r001/tree-sitter-leo) | unstable | `H IJ ` | @r001
[linkerscript](https://github.com/tree-sitter-grammars/tree-sitter-linkerscript) | unstable | `HFIJL` | @amaanq
[liquid](https://github.com/hankthetank27/tree-sitter-liquid) | unstable | `H  J ` | @hankthetank27
[liquidsoap](https://github.com/savonet/tree-sitter-liquidsoap) | unstable | `HFIJL` | @toots
[llvm](https://github.com/benwilliamgraham/tree-sitter-llvm) | unstable | `H  J ` | @benwilliamgraham
[lua](https://github.com/tree-sitter-grammars/tree-sitter-lua) | unstable | `HFIJL` | @muniftanjim
[luadoc](https://github.com/tree-sitter-grammars/tree-sitter-luadoc) | unstable | `H    ` | @amaanq
[luap](https://github.com/tree-sitter-grammars/tree-sitter-luap)[^luap] | unstable | `H    ` | @amaanq
[luau](https://github.com/tree-sitter-grammars/tree-sitter-luau) | unstable | `HFIJL` | @amaanq
[m68k](https://github.com/grahambates/tree-sitter-m68k) | unstable | `HF JL` | @grahambates
[make](https://github.com/tree-sitter-grammars/tree-sitter-make) | unstable | `HF J ` | @lewis6991
[markdown](https://github.com/tree-sitter-grammars/tree-sitter-markdown)[^markdown] | unstable | `HFIJ ` | @MDeiml
[markdown_inline](https://github.com/tree-sitter-grammars/tree-sitter-markdown)[^markdown_inline] | unstable | `H  J ` | @MDeiml
[matlab](https://github.com/acristoffers/tree-sitter-matlab) | unstable | `HFIJL` | @acristoffers
[menhir](https://github.com/Kerl13/tree-sitter-menhir) | unstable | `H  J ` | @Kerl13
[mermaid](https://github.com/monaqa/tree-sitter-mermaid) | unstable | `HFIJ ` |
[meson](https://github.com/tree-sitter-grammars/tree-sitter-meson) | unstable | `HFIJ ` | @Decodetalkers
[mlir](https://github.com/artagnon/tree-sitter-mlir) | unstable | `H  JL` | @artagnon
[muttrc](https://github.com/neomutt/tree-sitter-muttrc) | unstable | `H  J ` | @Freed-Wu
[nasm](https://github.com/naclsn/tree-sitter-nasm) | unstable | `H  J ` | @ObserverOfTime
[nginx](https://github.com/opa-oz/tree-sitter-nginx) | unstable | `HF J ` | @opa-oz
[nickel](https://github.com/nickel-lang/tree-sitter-nickel) | unstable | `H IJ ` |
[nim](https://github.com/alaviss/tree-sitter-nim) | unstable | `HF JL` | @aMOPel
[nim_format_string](https://github.com/aMOPel/tree-sitter-nim-format-string) | unstable | `H  J ` | @aMOPel
[ninja](https://github.com/alemuller/tree-sitter-ninja) | unstable | `HFIJ ` | @alemuller
[nix](https://github.com/nix-community/tree-sitter-nix) | unstable | `HFIJL` | @leo60228, @mrcjkb, @zimbatm
[nqc](https://github.com/tree-sitter-grammars/tree-sitter-nqc) | unstable | `HFIJL` | @amaanq
[nu](https://github.com/nushell/tree-sitter-nu) | unstable | `HFIJ ` | @abhisheksingh0x558
[objc](https://github.com/tree-sitter-grammars/tree-sitter-objc) | unstable | `HFIJL` | @amaanq
[objdump](https://github.com/ColinKennedy/tree-sitter-objdump) | unstable | `H  J ` | @ColinKennedy
[ocaml](https://github.com/tree-sitter/tree-sitter-ocaml) | unstable | `HFIJL` | @undu
[ocaml_interface](https://github.com/tree-sitter/tree-sitter-ocaml) | unstable | `HFIJL` | @undu
[ocamllex](https://github.com/atom-ocaml/tree-sitter-ocamllex) | unstable | `H  J ` | @undu
[odin](https://github.com/tree-sitter-grammars/tree-sitter-odin) | unstable | `HFIJL` | @amaanq
[pascal](https://github.com/Isopod/tree-sitter-pascal) | unstable | `HFIJL` | @Isopod
[passwd](https://github.com/ath3/tree-sitter-passwd) | unstable | `H    ` | @amaanq
[pem](https://github.com/tree-sitter-grammars/tree-sitter-pem) | unstable | `HF J ` | @ObserverOfTime
[perl](https://github.com/tree-sitter-perl/tree-sitter-perl) | unstable | `HF J ` | @RabbiVeesh, @LeoNerd
[php](https://github.com/tree-sitter/tree-sitter-php)[^php] | unstable | `HFIJL` | @tk-shirasaka, @calebdw
[php_only](https://github.com/tree-sitter/tree-sitter-php)[^php_only] | unstable | `HFIJL` | @tk-shirasaka, @calebdw
[phpdoc](https://github.com/claytonrcarter/tree-sitter-phpdoc) | unstable | `H    ` | @mikehaertl
[pioasm](https://github.com/leo60228/tree-sitter-pioasm) | unstable | `H  J ` | @leo60228
[pkl](https://github.com/apple/tree-sitter-pkl) | unstable | `HF J ` | @ribru17
[po](https://github.com/tree-sitter-grammars/tree-sitter-po) | unstable | `HF J ` | @amaanq
[pod](https://github.com/tree-sitter-perl/tree-sitter-pod) | unstable | `H    ` | @RabbiVeesh, @LeoNerd
[poe_filter](https://github.com/tree-sitter-grammars/tree-sitter-poe-filter)[^poe_filter] | unstable | `HFIJ ` | @ObserverOfTime
[pony](https://github.com/tree-sitter-grammars/tree-sitter-pony) | unstable | `HFIJL` | @amaanq, @mfelsche
[powershell](https://github.com/airbus-cert/tree-sitter-powershell) | unstable | `HFIJL` | @L2jLiga
[printf](https://github.com/tree-sitter-grammars/tree-sitter-printf) | unstable | `H    ` | @ObserverOfTime
[prisma](https://github.com/victorhqc/tree-sitter-prisma) | unstable | `HF J ` | @elianiva
[problog](https://github.com/foxyseta/tree-sitter-prolog) | unstable | `HFIJ ` | @foxyseta
[prolog](https://github.com/foxyseta/tree-sitter-prolog) | unstable | `HFIJ ` | @foxyseta
[promql](https://github.com/MichaHoffmann/tree-sitter-promql) | unstable | `H  J ` | @MichaHoffmann
[properties](https://github.com/tree-sitter-grammars/tree-sitter-properties)[^properties] | unstable | `H  JL` | @ObserverOfTime
[proto](https://github.com/coder3101/tree-sitter-proto) | unstable | `HFIJ ` | @stefanvanburen
[prql](https://github.com/PRQL/tree-sitter-prql) | unstable | `H  J ` | @matthias-Q
[psv](https://github.com/tree-sitter-grammars/tree-sitter-csv) | unstable | `H    ` | @amaanq
[pug](https://github.com/zealot128/tree-sitter-pug) | unstable | `H  J ` | @zealot128
[puppet](https://github.com/tree-sitter-grammars/tree-sitter-puppet) | unstable | `HFIJL` | @amaanq
[purescript](https://github.com/postsolar/tree-sitter-purescript) | unstable | `H  JL` | @postsolar
[pymanifest](https://github.com/tree-sitter-grammars/tree-sitter-pymanifest) | unstable | `H  J ` | @ObserverOfTime
[python](https://github.com/tree-sitter/tree-sitter-python) | stable | `HFIJL` | @stsewd, @theHamsta
[ql](https://github.com/tree-sitter/tree-sitter-ql) | unstable | `HFIJL` | @pwntester
[qmldir](https://github.com/tree-sitter-grammars/tree-sitter-qmldir) | unstable | `H  J ` | @amaanq
[qmljs](https://github.com/yuja/tree-sitter-qmljs) | unstable | `HF J ` | @Decodetalkers
[query](https://github.com/tree-sitter-grammars/tree-sitter-query)[^query] | unstable | `HFIJL` | @steelsojka
[r](https://github.com/r-lib/tree-sitter-r) | unstable | `H IJL` | @ribru17
[racket](https://github.com/6cdh/tree-sitter-racket) | unstable | `HF J ` |
[ralph](https://github.com/alephium/tree-sitter-ralph) | unstable | `H  J ` | @tdroxler
[rasi](https://github.com/Fymyte/tree-sitter-rasi) | unstable | `HFIJL` | @Fymyte
[razor](https://github.com/tris203/tree-sitter-razor) | unstable | `HF J ` | @tris203
[rbs](https://github.com/joker1007/tree-sitter-rbs) | unstable | `HFIJ ` | @joker1007
[re2c](https://github.com/tree-sitter-grammars/tree-sitter-re2c) | unstable | `HFIJL` | @amaanq
[readline](https://github.com/tree-sitter-grammars/tree-sitter-readline) | unstable | `HFIJ ` | @ribru17
[regex](https://github.com/tree-sitter/tree-sitter-regex) | unstable | `H    ` | @theHamsta
[rego](https://github.com/FallenAngel97/tree-sitter-rego) | unstable | `H  J ` | @FallenAngel97
[requirements](https://github.com/tree-sitter-grammars/tree-sitter-requirements) | unstable | `H  J ` | @ObserverOfTime
[rescript](https://github.com/rescript-lang/tree-sitter-rescript) | unstable | `HFIJL` | @ribru17
[rifleconf](https://github.com/purarue/tree-sitter-rifleconf) | unstable | `H  J ` | @purarue
[rnoweb](https://github.com/bamonroe/tree-sitter-rnoweb) | unstable | `HF J ` | @bamonroe
[robot](https://github.com/Hubro/tree-sitter-robot) | unmaintained | `HFIJ ` |
[robots_txt](https://github.com/opa-oz/tree-sitter-robots-txt) | unstable | `H  J ` | @opa-oz
[roc](https://github.com/faldor20/tree-sitter-roc) | unmaintained | `H IJL` |
[ron](https://github.com/tree-sitter-grammars/tree-sitter-ron) | unstable | `HFIJL` | @amaanq
[rst](https://github.com/stsewd/tree-sitter-rst) | unstable | `H  JL` | @stsewd
[ruby](https://github.com/tree-sitter/tree-sitter-ruby) | unstable | `HFIJL` | @TravonteD
[runescript](https://github.com/2004Scape/tree-sitter-runescript) | unstable | `H  J ` | @2004Scape
[rust](https://github.com/tree-sitter/tree-sitter-rust) | unstable | `HFIJL` | @amaanq
[scala](https://github.com/tree-sitter/tree-sitter-scala) | unstable | `HF JL` | @stevanmilic
[scfg](https://github.com/rockorager/tree-sitter-scfg) | unstable | `H  J ` | @WhyNotHugo
[scheme](https://github.com/6cdh/tree-sitter-scheme) | unstable | `HF J ` |
[scss](https://github.com/serenadeai/tree-sitter-scss) | unstable | `HFIJ ` | @elianiva
[sflog](https://github.com/aheber/tree-sitter-sfapex)[^sflog] | unstable | `H    ` | @aheber, @xixiaofinland
[slang](https://github.com/tree-sitter-grammars/tree-sitter-slang)[^slang] | unstable | `HFIJL` | @theHamsta
[slim](https://github.com/theoo/tree-sitter-slim) | unstable | `HFIJL` | @theoo
[slint](https://github.com/slint-ui/tree-sitter-slint) | unstable | `HFIJL` | @hunger
[smali](https://github.com/tree-sitter-grammars/tree-sitter-smali) | unstable | `HFIJL` | @amaanq
[smithy](https://github.com/indoorvivants/tree-sitter-smithy) | unstable | `H  J ` | @amaanq, @keynmol
[snakemake](https://github.com/osthomas/tree-sitter-snakemake) | unstable | `HFIJL` | @osthomas
[snl](https://github.com/minijackson/tree-sitter-snl)[^snl] | unstable | `HFIJL` | @minijackson
[solidity](https://github.com/JoranHonig/tree-sitter-solidity) | unstable | `HF J ` | @amaanq
[soql](https://github.com/aheber/tree-sitter-sfapex) | unstable | `H    ` | @aheber, @xixiafinland
[sosl](https://github.com/aheber/tree-sitter-sfapex) | unstable | `H    ` | @aheber, @xixiafinland
[sourcepawn](https://github.com/nilshelmig/tree-sitter-sourcepawn) | unstable | `H  JL` | @Sarrus1
[sparql](https://github.com/GordianDziwis/tree-sitter-sparql) | unstable | `HFIJL` | @GordianDziwis
[sproto](https://github.com/hanxi/tree-sitter-sproto) | unstable | `HFIJ ` | @hanxi
[sql](https://github.com/derekstride/tree-sitter-sql) | unstable | `HFIJ ` | @derekstride
[squirrel](https://github.com/tree-sitter-grammars/tree-sitter-squirrel) | unstable | `HFIJL` | @amaanq
[ssh_config](https://github.com/tree-sitter-grammars/tree-sitter-ssh-config) | unstable | `HFIJL` | @ObserverOfTime
[starlark](https://github.com/tree-sitter-grammars/tree-sitter-starlark) | unstable | `HFIJL` | @amaanq
[strace](https://github.com/sigmaSd/tree-sitter-strace) | unstable | `H  J ` | @amaanq
[styled](https://github.com/mskelton/tree-sitter-styled) | unstable | `HFIJ ` | @mskelton
[supercollider](https://github.com/madskjeldgaard/tree-sitter-supercollider) | unstable | `HFIJL` | @madskjeldgaard, @elgiano
[superhtml](https://github.com/kristoff-it/superhtml) | unstable | `H  J ` | @rockorager
[surface](https://github.com/connorlay/tree-sitter-surface) | unstable | `HFIJ ` | @connorlay
[svelte](https://github.com/tree-sitter-grammars/tree-sitter-svelte) | unstable | `HFIJL` | @amaanq
[sway](https://github.com/FuelLabs/tree-sitter-sway.git) | unstable | `HFIJL` | @ribru17
[swift](https://github.com/alex-pinkus/tree-sitter-swift) | unstable | `HFIJL` | @alex-pinkus
[sxhkdrc](https://github.com/RaafatTurki/tree-sitter-sxhkdrc) | unstable | `HF J ` | @RaafatTurki
[systemtap](https://github.com/ok-ryoko/tree-sitter-systemtap) | unstable | `HF JL` | @ok-ryoko
[systemverilog](https://github.com/gmlarumbe/tree-sitter-systemverilog) | unstable | `HF J ` | @zhangwwpeng
[t32](https://github.com/xasc/tree-sitter-t32) | unstable | `HFIJL` | @xasc
[tablegen](https://github.com/tree-sitter-grammars/tree-sitter-tablegen) | unstable | `HFIJL` | @amaanq
[tact](https://github.com/tact-lang/tree-sitter-tact) | unstable | `HFIJL` | @novusnota
[tcl](https://github.com/tree-sitter-grammars/tree-sitter-tcl) | unstable | `HFIJ ` | @lewis6991
[teal](https://github.com/euclidianAce/tree-sitter-teal) | unstable | `HFIJL` | @euclidianAce
[templ](https://github.com/vrischmann/tree-sitter-templ) | unstable | `HF J ` | @vrischmann
[tera](https://github.com/uncenter/tree-sitter-tera) | unstable | `H  J ` | @uncenter
[terraform](https://github.com/MichaHoffmann/tree-sitter-hcl) | unstable | `HFIJ ` | @MichaHoffmann
[textproto](https://github.com/PorterAtGoogle/tree-sitter-textproto) | unstable | `HFIJ ` | @Porter
[thrift](https://github.com/tree-sitter-grammars/tree-sitter-thrift) | unstable | `HFIJL` | @amaanq, @duskmoon314
[tiger](https://github.com/ambroisie/tree-sitter-tiger) | unstable | `HFIJL` | @ambroisie
[tlaplus](https://github.com/tlaplus-community/tree-sitter-tlaplus) | unstable | `HF JL` | @ahelwer, @susliko
[tmux](https://github.com/Freed-Wu/tree-sitter-tmux) | unstable | `H  J ` | @Freed-Wu, @stevenxxiu
[todotxt](https://github.com/arnarg/tree-sitter-todotxt) | unstable | `H    ` | @arnarg
[toml](https://github.com/tree-sitter-grammars/tree-sitter-toml) | unstable | `HFIJL` | @tk-shirasaka
[tsv](https://github.com/tree-sitter-grammars/tree-sitter-csv) | unstable | `H    ` | @amaanq
[tsx](https://github.com/tree-sitter/tree-sitter-typescript) | unstable | `HFIJL` | @steelsojka
[turtle](https://github.com/GordianDziwis/tree-sitter-turtle) | unstable | `HFIJL` | @GordianDziwis
[twig](https://github.com/gbprod/tree-sitter-twig) | unstable | `H  J ` | @gbprod
[typescript](https://github.com/tree-sitter/tree-sitter-typescript) | unstable | `HFIJL` | @steelsojka
[typespec](https://github.com/happenslol/tree-sitter-typespec) | unstable | `H IJ ` | @happenslol
[typoscript](https://github.com/Teddytrombone/tree-sitter-typoscript) | unstable | `HFIJ ` | @Teddytrombone
[typst](https://github.com/uben0/tree-sitter-typst) | unstable | `HFIJ ` | @uben0, @RaafatTurki
[udev](https://github.com/tree-sitter-grammars/tree-sitter-udev) | unstable | `H  JL` | @ObserverOfTime
[ungrammar](https://github.com/tree-sitter-grammars/tree-sitter-ungrammar) | unstable | `HFIJL` | @Philipp-M, @amaanq
[unison](https://github.com/kylegoetz/tree-sitter-unison) | unstable | `HF J ` | @tapegram
[usd](https://github.com/ColinKennedy/tree-sitter-usd) | unstable | `HFIJL` | @ColinKennedy
[uxntal](https://github.com/tree-sitter-grammars/tree-sitter-uxntal) | unstable | `HFIJL` | @amaanq
[v](https://github.com/vlang/v-analyzer) | unstable | `HFIJL` | @kkharji, @amaanq
[vala](https://github.com/vala-lang/tree-sitter-vala) | unstable | `HF J ` | @Prince781
[vento](https://github.com/ventojs/tree-sitter-vento) | unmaintained | `H  J ` |
[vhdl](https://github.com/jpt13653903/tree-sitter-vhdl) | unstable | `HF J ` | @jpt13653903
[vhs](https://github.com/charmbracelet/tree-sitter-vhs) | unstable | `H  J ` | @caarlos0
[vim](https://github.com/tree-sitter-grammars/tree-sitter-vim) | unstable | `HF JL` | @clason
[vimdoc](https://github.com/neovim/tree-sitter-vimdoc) | unstable | `H  J ` | @clason
[vrl](https://github.com/belltoy/tree-sitter-vrl) | unstable | `HFIJL` | @belltoy
[vue](https://github.com/tree-sitter-grammars/tree-sitter-vue) | unstable | `HFIJ ` | @WhyNotHugo, @lucario387
[wgsl](https://github.com/szebniok/tree-sitter-wgsl) | unstable | `HFIJ ` | @szebniok
[wgsl_bevy](https://github.com/tree-sitter-grammars/tree-sitter-wgsl-bevy) | unstable | `HFI  ` | @theHamsta
[wing](https://github.com/winglang/tree-sitter-wing) | unstable | `HF JL` | @gshpychka, @MarkMcCulloh
[wit](https://github.com/bytecodealliance/tree-sitter-wit) | stable | `HF J ` | @mkatychev
[wxml](https://github.com/BlockLune/tree-sitter-wxml) | unstable | `HFIJ ` | @BlockLune
[xcompose](https://github.com/tree-sitter-grammars/tree-sitter-xcompose) | unstable | `H  JL` | @ObserverOfTime
[xml](https://github.com/tree-sitter-grammars/tree-sitter-xml) | unstable | `HFIJL` | @ObserverOfTime
[xresources](https://github.com/ValdezFOmar/tree-sitter-xresources) | stable | `HF JL` | @ValdezFOmar
[yaml](https://github.com/tree-sitter-grammars/tree-sitter-yaml) | unstable | `HFIJL` | @amaanq
[yang](https://github.com/Hubro/tree-sitter-yang) | unstable | `HFIJ ` | @Hubro
[yuck](https://github.com/tree-sitter-grammars/tree-sitter-yuck) | unstable | `HFIJL` | @Philipp-M, @amaanq
[zathurarc](https://github.com/Freed-Wu/tree-sitter-zathurarc) | unstable | `H  J ` | @Freed-Wu
[zig](https://github.com/tree-sitter-grammars/tree-sitter-zig) | unstable | `HFIJL` | @amaanq
[ziggy](https://github.com/kristoff-it/ziggy) | unmaintained | `H I  ` |
[ziggy_schema](https://github.com/kristoff-it/ziggy) | unmaintained | `H I  ` |
[zsh](https://github.com/georgeharker/tree-sitter-zsh) | unstable | `HF JL` | @georgeharker
[^bp]: Android Blueprint
[^ecma]: queries required by javascript, typescript, tsx, qmljs
[^gap]: GAP system
[^gaptst]: GAP system test files
[^gdscript]: Godot
[^glimmer]: Glimmer and Ember
[^godot_resource]: Godot Resources
[^html_tags]: queries required by html, astro, vue, svelte
[^jinja]: basic highlighting
[^jinja_inline]: needed for full highlighting
[^jsx]: queries required by javascript, tsx
[^luap]: Lua patterns
[^markdown]: basic highlighting
[^markdown_inline]: needed for full highlighting
[^php]: PHP with embedded HTML
[^php_only]: PHP without embedded HTML
[^poe_filter]: Path of Exile item filter
[^properties]: Java properties files
[^query]: Tree-sitter query language
[^sflog]: Salesforce debug log
[^slang]: Shader Slang
[^snl]: EPICS Sequencer's SNL files
<!--parserinfo-->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View file

@ -1,27 +0,0 @@
function! nvim_treesitter#statusline(...) abort
return luaeval("require'nvim-treesitter.statusline'.statusline(_A)", get(a:, 1, {}))
endfunction
function! nvim_treesitter#foldexpr() abort
return luaeval(printf('require"nvim-treesitter.fold".get_fold_indic(%d)', v:lnum))
endfunction
function! nvim_treesitter#installable_parsers(arglead, cmdline, cursorpos) abort
return join(luaeval("require'nvim-treesitter.parsers'.available_parsers()") + ['all'], "\n")
endfunction
function! nvim_treesitter#installed_parsers(arglead, cmdline, cursorpos) abort
return join(luaeval("require'nvim-treesitter.info'.installed_parsers()") + ['all'], "\n")
endfunction
function! nvim_treesitter#available_modules(arglead, cmdline, cursorpos) abort
return join(luaeval("require'nvim-treesitter.configs'.available_modules()"), "\n")
endfunction
function! nvim_treesitter#available_query_groups(arglead, cmdline, cursorpos) abort
return join(luaeval("require'nvim-treesitter.query'.available_query_groups()"), "\n")
endfunction
function! nvim_treesitter#indent() abort
return luaeval(printf('require"nvim-treesitter.indent".get_indent(%d)', v:lnum))
endfunction

View file

@ -1,41 +0,0 @@
local git_ref = '$git_ref'
local modrev = '$modrev'
local specrev = '-1'
local repo_url = '$repo_url'
rockspec_format = '3.0'
package = '$package'
version = modrev .. specrev
description = {
summary = 'Nvim Treesitter configurations and abstraction layer',
detailed = $detailed_description,
labels = { 'neovim' },
homepage = 'https://github.com/nvim-treesitter/nvim-treesitter',
license = 'Apache-2.0',
}
dependencies = {
'lua >= 5.1',
}
-- source = file:///.
source = {
url = repo_url .. '/archive/' .. git_ref .. '.zip',
dir = '$repo_name-' .. '$archive_dir_suffix',
}
build = {
type = 'make',
build_pass = false,
install_variables = {
INST_PREFIX='$(PREFIX)',
INST_BINDIR='$(BINDIR)',
INST_LIBDIR='$(LIBDIR)',
INST_LUADIR='$(LUADIR)',
INST_CONFDIR='$(CONFDIR)',
},
copy_directories = $copy_directories,
}

View file

@ -1,36 +0,0 @@
local MODREV, SPECREV = 'scm', '-1'
rockspec_format = '3.0'
package = 'nvim-treesitter'
version = MODREV .. SPECREV
description = {
summary = 'Nvim Treesitter configurations and abstraction layer',
labels = { 'neovim' },
homepage = 'https://github.com/nvim-treesitter/nvim-treesitter',
license = 'Apache-2.0',
}
dependencies = {
'lua >= 5.1',
}
source = {
url = 'git://github.com/nvim-treesitter/nvim-treesitter',
}
build = {
type = 'make',
install_variables = {
INST_PREFIX='$(PREFIX)',
INST_BINDIR='$(BINDIR)',
INST_LIBDIR='$(LIBDIR)',
INST_LUADIR='$(LUADIR)',
INST_CONFDIR='$(CONFDIR)',
},
copy_directories = {
'autoload',
'doc',
'plugin',
'queries'
}
}

View file

@ -1,6 +1,4 @@
*nvim-treesitter* Treesitter configurations and abstraction layer for Neovim.
Minimum version of neovim: nightly
*nvim-treesitter.txt* Treesitter parser and query installer for Neovim
Authors:
Kiyan Yazdani <yazdani.kiyan@protonmail.com>
@ -13,578 +11,179 @@ Authors:
Type |gO| to see the table of contents.
==============================================================================
INTRODUCTION *nvim-treesitter-intro*
INTRODUCTION *nvim-treesitter-intro*
nvim-treesitter wraps the Neovim treesitter API to provide functionalities
such as highlighting and incremental selection, and a command to easily
install parsers.
Nvim-treesitter provides functionalities for managing treesitter parsers and
compatible queries for core features (highlighting, injections, folds,
indents).
==============================================================================
QUICK START *nvim-treesitter-quickstart*
QUICK START *nvim-treesitter-quickstart*
Install the parser for your language
>
:TSInstall {language}
<
To get a list of supported languages
>
:TSInstallInfo
<
By default, everything is disabled.
To enable supported features, put this in your `init.lua` file:
>
require'nvim-treesitter.configs'.setup {
-- A directory to install the parsers into.
-- If this is excluded or nil parsers are installed
-- to either the package dir, or the "site" dir.
-- If a custom path is used (not nil) it must be added to the runtimepath.
parser_install_dir = "/some/path/to/store/parsers",
-- A list of parser names, or "all"
ensure_installed = { "c", "lua", "rust" },
-- Install parsers synchronously (only applied to `ensure_installed`)
sync_install = false,
-- Automatically install missing parsers when entering buffer
auto_install = false,
-- List of parsers to ignore installing (for "all")
ignore_install = { "javascript" },
highlight = {
-- `false` will disable the whole extension
enable = true,
-- list of language that will be disabled
disable = { "c", "rust" },
-- Setting this to true will run `:h syntax` and tree-sitter at the same time.
-- Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
-- Using this option may slow down your editor, and you may see some duplicate highlights.
-- Instead of true it can also be a list of languages
additional_vim_regex_highlighting = false,
},
To configure `nvim-treesitter`, put this in your `init.lua` file:
>lua
require'nvim-treesitter'.setup {
-- A directory to install the parsers and queries to.
-- Defaults to the `stdpath('data')/site` dir.
install_dir = "/some/path/to/store/parsers",
}
vim.opt.runtimepath:append("/some/path/to/store/parsers")
<
See |nvim-treesitter-modules| for a list of all available modules and its options.
NOTE: You do not need to call `setup` to use this plugin with the default
settings!
Parsers and queries can then be installed with >lua
require'nvim-treesitter'.install { 'rust', 'javascript', 'zig' }
<
To check installed parsers and queries, use `:checkhealth nvim-treesitter`.
Treesitter features for installed languages need to be enabled manually in a
|FileType| autocommand or |ftplugin|, e.g. >lua
vim.api.nvim_create_autocmd('FileType', {
pattern = { 'rust', 'javascript', 'zig' },
callback = function()
-- syntax highlighting, provided by Neovim
vim.treesitter.start()
-- folds, provided by Neovim
vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()'
vim.wo.foldmethod = 'expr'
-- indentation, provided by nvim-treesitter
vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
end,
})
<
==============================================================================
COMMANDS *nvim-treesitter-commands*
:TSInstall {language} *:TSInstall*
Install one or more treesitter parsers. {language} can be one or multiple
parsers or tiers (`stable`, `unstable`, or `all` (not recommended)). This is a
no-op if the parser(s) are already installed. Installation is performed
asynchronously. Use *:TSInstall!* to force installation even if a parser is
already installed.
:TSInstallFromGrammar {language} *:TSInstallFromGrammar*
Like |:TSInstall| but also regenerates the `parser.c` from the original
grammar. Useful for languages where the provided `parser.c` is outdated (e.g.,
uses a no longer supported ABI).
:TSUpdate [{language}] *:TSUpdate*
Update parsers to the `revision` specified in the manifest if this is newer
than the installed version. If {language} is specified, update the
corresponding parser or tier; otherwise update all installed parsers. This is
a no-op if all (specified) parsers are up to date.
Note: It is recommended to add this command as a build step in your plugin
manager.
:TSUninstall {language} *:TSUninstall*
Deletes the parser for one or more {language}, or all parsers with `all`.
:TSLog *:TSLog*
Shows all messages from previous install, update, or uninstall operations.
==============================================================================
MODULES *nvim-treesitter-modules*
API *nvim-treesitter-api*
|nvim-treesitter| provides several functionalities via modules (and submodules),
each module makes use of the query files defined for each language,
setup({opts}) *nvim-treesitter.setup()*
All modules are disabled by default, and some provide default keymaps.
Each module corresponds to an entry in the dictionary passed to the
`nvim-treesitter.configs.setup` function, this should be in your `init.lua` file.
Configure installation options. Needs to be specified before any
installation operation.
>
require'nvim-treesitter.configs'.setup {
-- Modules and its options go here
highlight = { enable = true },
incremental_selection = { enable = true },
textobjects = { enable = true },
}
Note: You only need to call `setup` if you want to set non-default
options!
Parameters: ~
• {opts} `(table?)` Optional parameters:
• {install_dir} (`string?`, default `stdpath('data')/site/`)
directory to install parsers and queries to. Note: will be
prepended to |runtimepath|.
install({languages} [, {opts}]) *nvim-treesitter.install()*
Download, compile, and install the specified treesitter parsers and copy
the corresponding queries to a directory on |runtimepath|, enabling their
use in Neovim.
Note: This operation is performed asynchronously by default. For
synchronous operation (e.g., in a bootstrapping script), you need to
`wait()` for it: >lua
require('nvim-treesitter').install({ 'rust', 'javascript', 'zig' })
:wait(300000) -- max. 5 minutes
<
Parameters: ~
• {languages} `(string[]|string)` (List of) languages or tiers (`stable`,
`unstable`) to install.
• {opts} `(table?)` Optional parameters:
• {force} (`boolean?`, default `false`) force installation
of already installed parsers
• {generate} (`boolean?`, default `false`) generate
`parser.c` from `grammar.json` or `grammar.js` before
compiling.
• {max_jobs} (`integer?`) limit parallel tasks (useful in
combination with {generate} on memory-limited systems).
• {summary} (`boolean?`, default `false`) print summary of
successful and total operations for multiple languages.
All modules share some common options, like `enable` and `disable`.
When `enable` is `true` this will enable the module for all supported languages,
if you want to disable the module for some languages you can pass a list to the `disable` option.
uninstall({languages} [, {opts}]) *nvim-treesitter.uninstall()*
>
require'nvim-treesitter.configs'.setup {
highlight = {
enable = true,
disable = { "cpp", "lua" },
},
}
Remove the parser and queries for the specified language(s).
Parameters: ~
• {languages} `(string[]|string)` (List of) languages or tiers (`stable`,
`unstable`) to update.
• {opts} `(table?)` Optional parameters:
• {summary} (`boolean?`, default `false`) print summary of
successful and total operations for multiple languages.
update([{languages}, {opts}]) *nvim-treesitter.update()*
Update the parsers and queries if older than the revision specified in the
manifest.
Note: This operation is performed asynchronously by default. For
synchronous operation (e.g., in a bootstrapping script), you need to
`wait()` for it: >lua
require('nvim-treesitter').update():wait(300000) -- max. 5 minutes
<
Parameters: ~
• {languages} `(string[]|string)?` (List of) languages or tiers to update
(default: all installed).
• {opts} `(table?)` Optional parameters:
• {max_jobs} (`integer?`) limit parallel tasks (useful in
combination with {generate} on memory-limited systems).
• {summary} (`boolean?`, default `false`) print summary of
successful and total operations for multiple languages.
For more fine-grained control, `disable` can also take a function and
whenever it returns `true`, the module is disabled for that buffer.
The function is called once when a module starts in a buffer and receives the
language and buffer number as arguments:
indentexpr() *nvim-treesitter.indentexpr()*
>
require'nvim-treesitter.configs'.setup {
highlight = {
enable = true,
disable = function(lang, bufnr) -- Disable in large C++ buffers
return lang == "cpp" and vim.api.nvim_buf_line_count(bufnr) > 50000
end,
},
}
Used to enable treesitter indentation for a language via >lua
vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
<
get_available([{tier}]) *nvim-treesitter.get_available()*
Options that define or accept a keymap use the same format you use to define
keymaps in Neovim, so you can write keymaps as `gd`, `<space>a`, `<leader>a`
`<C-a>` (control + a), `<A-n>` (alt + n), `<CR>` (enter), etc.
Return list of languages available for installation.
External plugins can provide their own modules with their own options,
those can also be configured using the `nvim-treesitter.configs.setup`
function.
Parameters: ~
• {tier} `(integer?)` Only return languages of specified {tier} (`1`:
stable, `2`: unstable, `3`: unmaintained, `4`: unsupported)
------------------------------------------------------------------------------
HIGHLIGHT *nvim-treesitter-highlight-mod*
get_installed([{type}]) *nvim-treesitter.get_installed()*
Consistent syntax highlighting.
Return list of languages installed via `nvim-treesitter`.
Query files: `highlights.scm`.
Supported options:
- enable: `true` or `false`.
- disable: list of languages.
- additional_vim_regex_highlighting: `true` or `false`, or a list of languages.
Set this to `true` if you depend on 'syntax' being enabled
(like for indentation). Using this option may slow down your editor,
and you may see some duplicate highlights.
Defaults to `false`.
>
require'nvim-treesitter.configs'.setup {
highlight = {
enable = true,
custom_captures = {
-- Highlight the @foo.bar capture group with the "Identifier" highlight group.
["foo.bar"] = "Identifier",
},
-- Setting this to true or a list of languages will run `:h syntax` and tree-sitter at the same time.
additional_vim_regex_highlighting = false,
},
}
Note: This only searches `nvim-treesitter`'s (configured or default)
installation directory; parsers and queries from other sources can be
placed anywhere on 'runtimepath' and are not included. To list all, e.g.,
parsers that are installed from any source, use >lua
vim.api.nvim_get_runtime_file('parser/*', true)
<
You can also set custom highlight captures
>
lua <<EOF
require"nvim-treesitter.highlight".set_custom_captures {
-- Highlight the @foo.bar capture group with the "Identifier" highlight group.
["foo.bar"] = "Identifier",
}
EOF
<
Note: The api is not stable yet.
------------------------------------------------------------------------------
INCREMENTAL SELECTION *nvim-treesitter-incremental-selection-mod*
Incremental selection based on the named nodes from the grammar.
Query files: `locals.scm`.
Supported options:
- enable: `true` or `false`.
- disable: list of languages.
- keymaps:
- init_selection: in normal mode, start incremental selection.
Defaults to `gnn`.
- node_incremental: in visual mode, increment to the upper named parent.
Defaults to `grn`.
- scope_incremental: in visual mode, increment to the upper scope
(as defined in `locals.scm`). Defaults to `grc`.
- node_decremental: in visual mode, decrement to the previous named node.
Defaults to `grm`.
>
require'nvim-treesitter.configs'.setup {
incremental_selection = {
enable = true,
keymaps = {
init_selection = "gnn",
node_incremental = "grn",
scope_incremental = "grc",
node_decremental = "grm",
},
},
}
<
------------------------------------------------------------------------------
INDENTATION *nvim-treesitter-indentation-mod*
Indentation based on treesitter for the |=| operator.
NOTE: this is an experimental feature.
Query files: `indents.scm`.
Supported options:
- enable: `true` or `false`.
- disable: list of languages.
>
require'nvim-treesitter.configs'.setup {
indent = {
enable = true
},
}
`@indent` *nvim-treesitter-indentation-queries*
Queries can use the following captures: `@indent.begin` and `@indent.dedent`,
`@indent.branch`, `@indent.end` or `@indent.align`. An `@indent.ignore` capture tells
treesitter to ignore indentation and a `@indent.zero` capture sets
the indentation to 0.
`@indent.begin` *nvim-treesitter-indentation-indent.begin*
The `@indent.begin` specifies that the next line should be indented. Multiple
indents on the same line get collapsed. Eg.
>
(
(if_statement)
(ERROR "else") @indent.begin
)
<
Indent can also have `indent.immediate` set using a `#set!` directive, which
permits the next line to indent even when the block intended to be indented
has no content yet, improving interactive typing.
eg for python:
>
((if_statement) @indent.begin
(#set! indent.immediate 1))
<
Will allow:
>
if True:<CR>
# Auto indent to here
`@indent.end` *nvim-treesitter-indentation-indent.end*
An `@indent.end` capture is used to specify that the indented region ends and
any text subsequent to the capture should be dedented.
`@indent.branch` *nvim-treesitter-indentation-indent.branch*
An `@indent.branch` capture is used to specify that a dedented region starts
at the line including the captured nodes.
`@indent.dedent` *nvim-treesitter-indentation-indent.dedent*
A `@indent.dedent` capture specifies dedenting starting on the next line.
>
`@indent.align` *nvim-treesitter-indentation-aligned_indent.align*
Aligned indent blocks may be specified with the `@indent.align` capture.
This permits
>
foo(a,
b,
c)
<
As well as
>
foo(
a,
b,
c)
<
and finally
>
foo(
a,
b,
c
)
<
To specify the delimiters to use `indent.open_delimiter` and
`indent.close_delimiter` should be used. Eg.
>
((argument_list) @indent.align
(#set! indent.open_delimiter "(")
(#set! indent.close_delimiter ")"))
<
For some languages the last line of an `indent.align` block must not be
the same indent as the natural next line.
For example in python:
>
if (a > b and
c < d):
pass
Is not correct, whereas
>
if (a > b and
c < d):
pass
Would be correctly indented. This behavior may be chosen using
`indent.avoid_last_matching_next`. Eg.
>
(if_statement
condition: (parenthesized_expression) @indent.align
(#set! indent.open_delimiter "(")
(#set! indent.close_delimiter ")")
(#set! indent.avoid_last_matching_next 1)
)
<
Could be used to specify that the last line of an `@indent.align` capture
should be additionally indented to avoid clashing with the indent of the first
line of the block inside an if.
==============================================================================
COMMANDS *nvim-treesitter-commands*
*:TSInstall*
:TSInstall {language} ...~
Install one or more treesitter parsers.
You can use |:TSInstall| `all` to install all parsers. Use |:TSInstall!| to
force the reinstallation of already installed parsers.
*:TSInstallSync*
:TSInstallSync {language} ...~
Perform the |:TSInstall| operation synchronously.
*:TSInstallInfo*
:TSInstallInfo~
List information about currently installed parsers
*:TSUpdate*
:TSUpdate {language} ...~
Update the installed parser for one more {language} or all installed parsers
if {language} is omitted. The specified parser is installed if it is not already
installed.
*:TSUpdateSync*
:TSUpdateSync {language} ...~
Perform the |:TSUpdate| operation synchronously.
*:TSUninstall*
:TSUninstall {language} ...~
Deletes the parser for one or more {language}. You can use 'all' for language
to uninstall all parsers.
*:TSBufEnable*
:TSBufEnable {module}~
Enable {module} on the current buffer.
A list of modules can be found at |:TSModuleInfo|
*:TSBufDisable*
:TSBufDisable {module}~
Disable {module} on the current buffer.
A list of modules can be found at |:TSModuleInfo|
*:TSBufToggle*
:TSBufToggle {module}~
Toggle (enable if disabled, disable if enabled) {module} on the current
buffer.
A list of modules can be found at |:TSModuleInfo|
*:TSEnable*
:TSEnable {module} [{language}]~
Enable {module} for the session.
If {language} is specified, enable module for the session only for this
particular language.
A list of modules can be found at |:TSModuleInfo|
A list of languages can be found at |:TSInstallInfo|
*:TSDisable*
:TSDisable {module} [{language}]~
Disable {module} for the session.
If {language} is specified, disable module for the session only for this
particular language.
A list of modules can be found at |:TSModuleInfo|
A list of languages can be found at |:TSInstallInfo|
*:TSToggle*
:TSToggle {module} [{language}]~
Toggle (enable if disabled, disable if enabled) {module} for the session.
If {language} is specified, toggle module for the session only for this
particular language.
A list of modules can be found at |:TSModuleInfo|
A list of languages can be found at |:TSInstallInfo|
*:TSModuleInfo*
:TSModuleInfo [{module}]~
List the state for the given module or all modules for the current session in
a new buffer.
These highlight groups are used by default:
>
highlight default TSModuleInfoGood guifg=LightGreen gui=bold
highlight default TSModuleInfoBad guifg=Crimson
highlight default link TSModuleInfoHeader Type
highlight default link TSModuleInfoNamespace Statement
highlight default link TSModuleInfoParser Identifier
<
*:TSEditQuery*
:TSEditQuery {query-group} [{lang}]~
Edit the query file for a {query-group} (e.g. highlights, locals) for given
{lang}. If there are multiple files, the user is prompted to select one of them.
If no such file exists, a buffer for a new file in the user's config directory
is created. If {lang} is not specified, the language of the current buffer
is used.
*:TSEditQueryUserAfter*
:TSEditQueryUserAfter {query-group} [{lang}]~
Same as |:TSEditQuery| but edits a file in the `after` directory of the
user's config directory. Useful to add custom extensions for the queries
provided by a plugin.
==============================================================================
UTILS *nvim-treesitter-utils*
Nvim treesitter has some wrapper functions that you can retrieve with:
>
local ts_utils = require 'nvim-treesitter.ts_utils'
<
Methods
*ts_utils.get_node_at_cursor*
get_node_at_cursor(winnr)~
`winnr` will be 0 if nil.
Returns the node under the cursor.
*ts_utils.is_parent*
is_parent(dest, source)~
Determines whether `dest` is a parent of `source`.
Returns a boolean.
*ts_utils.get_named_children*
get_named_children(node)~
Returns a table of named children of `node`.
*ts_utils.get_next_node*
get_next_node(node, allow_switch_parent, allow_next_parent)~
Returns the next node within the same parent.
If no node is found, returns `nil`.
If `allow_switch_parent` is true, it will allow switching parent
when the node is the last node.
If `allow_next_parent` is true, it will allow next parent if
the node is the last node and the next parent doesn't have children.
*ts_utils.get_previous_node*
get_previous_node(node, allow_switch_parents, allow_prev_parent)~
Returns the previous node within the same parent.
`allow_switch_parent` and `allow_prev_parent` follow the same rule
as |ts_utils.get_next_node| but if the node is the first node.
*ts_utils.goto_node*
goto_node(node, goto_end, avoid_set_jump)~
Sets cursor to the position of `node` in the current windows.
If `goto_end` is truthy, the cursor is set to the end the node range.
Setting `avoid_set_jump` to `true`, avoids setting the current cursor position
to the jump list.
*ts_utils.swap_nodes*
swap_nodes(node_or_range1, node_or_range2, bufnr, cursor_to_second)~
Swaps the nodes or ranges.
set `cursor_to_second` to true to move the cursor to the second node
*ts_utils.memoize_by_buf_tick*
memoize_by_buf_tick(fn, options)~
Caches the return value for a function and returns the cache value if the tick
of the buffer has not changed from the previous.
`fn`: a function that takes any arguments
and returns a value to store.
`options?`: <table>
- `bufnr`: a function/value that extracts the bufnr from the given arguments.
- `key`: a function/value that extracts the cache key from the given arguments.
`returns`: a function to call with bufnr as argument to
retrieve the value from the cache
*ts_utils.node_to_lsp_range*
node_to_lsp_range(node)~
Get an lsp formatted range from a node range
*ts_utils.node_length*
node_length(node)~
Get the byte length of node range
*ts_utils.update_selection*
update_selection(buf, node)~
Set the selection to the node range
*ts_utils.highlight_range*
highlight_range(range, buf, hl_namespace, hl_group)~
Set a highlight that spans the given range
*ts_utils.highlight_node*
highlight_node(node, buf, hl_namespace, hl_group)~
Set a highlight that spans the given node's range
==============================================================================
FUNCTIONS *nvim-treesitter-functions*
*nvim_treesitter#statusline()*
nvim_treesitter#statusline(opts)~
Returns a string describing the current position in the file. This
could be used as a statusline indicator.
Default options (lua syntax):
>
{
indicator_size = 100,
type_patterns = {'class', 'function', 'method'},
transform_fn = function(line, _node) return line:gsub('%s*[%[%(%{]*%s*$', '') end,
separator = ' -> ',
allow_duplicates = false
}
<
- `indicator_size` - How long should the string be. If longer, it is cut from
the beginning.
- `type_patterns` - Which node type patterns to match.
- `transform_fn` - Function used to transform the single item in line. By
default it removes opening brackets and spaces from end. Takes two arguments:
the text of the line in question, and the corresponding treesitter node.
- `separator` - Separator between nodes.
- `allow_duplicates` - Whether or not to remove duplicate components.
*nvim_treesitter#foldexpr()*
nvim_treesitter#foldexpr()~
Functions to be used to determine the fold level at a given line number.
To use it: >
set foldmethod=expr
set foldexpr=nvim_treesitter#foldexpr()
<
This will respect your 'foldminlines' and 'foldnestmax' settings.
Note: This is highly experimental, and folding can break on some types of
edits. If you encounter such breakage, hitting `zx` should fix folding.
In any case, feel free to open an issue with the reproducing steps.
==============================================================================
PERFORMANCE *nvim-treesitter-performance*
`nvim-treesitter` checks the 'runtimepath' on startup in order to discover
available parsers and queries and index them. As a consequence, a very long
'runtimepath' might result in delayed startup times.
Parameters: ~
• {type} `('queries'|parsers'?)` If specified, only show languages with
installed queries or parsers, respectively.
vim:tw=78:ts=8:expandtab:noet:ft=help:norl:

View file

@ -1,959 +0,0 @@
{
"ada": {
"revision": "e8e2515465cc2d7c444498e68bdb9f1d86767f95"
},
"agda": {
"revision": "b9b32fa042c2952a7bfca86847ea325e44ccc897"
},
"angular": {
"revision": "843525141575e397541e119698f0532755e959f6"
},
"apex": {
"revision": "3597575a429766dd7ecce9f5bb97f6fec4419d5d"
},
"arduino": {
"revision": "017696bdf47ca2b10948c5a511f9ab387722d0f3"
},
"asm": {
"revision": "04962e15f6b464cf1d75eada59506dc25090e186"
},
"astro": {
"revision": "0ad33e32ae9726e151d16ca20ba3e507ff65e01f"
},
"authzed": {
"revision": "1dec7e1af96c56924e3322cd85fdce15d0a31d00"
},
"awk": {
"revision": "34bbdc7cce8e803096f47b625979e34c1be38127"
},
"bash": {
"revision": "0c46d792d54c536be5ff7eb18eb95c70fccdb232"
},
"bass": {
"revision": "28dc7059722be090d04cd751aed915b2fee2f89a"
},
"beancount": {
"revision": "9bc460a05b5f096d69568b5fb36105032ff4ff97"
},
"bibtex": {
"revision": "ccfd77db0ed799b6c22c214fe9d2937f47bc8b34"
},
"bicep": {
"revision": "bff59884307c0ab009bd5e81afd9324b46a6c0f9"
},
"bitbake": {
"revision": "a5d04fdb5a69a02b8fa8eb5525a60dfb5309b73b"
},
"blade": {
"revision": "bcdc4b01827cac21205f7453e9be02f906943128"
},
"blueprint": {
"revision": "60ba73739c6083c693d86a1a7cf039c07eb4ed59"
},
"bp": {
"revision": "16c43068ec30828c5aed11e87262c56f36782595"
},
"brightscript": {
"revision": "48ce1687125c6dfefcc7a1bef19fa0f0f00426cc"
},
"c": {
"revision": "2a265d69a4caf57108a73ad2ed1e6922dd2f998c"
},
"c_sharp": {
"revision": "b5eb5742f6a7e9438bee22ce8026d6b927be2cd7"
},
"caddy": {
"revision": "2686186edb61be47960431c93a204fb249681360"
},
"cairo": {
"revision": "6238f609bea233040fe927858156dee5515a0745"
},
"capnp": {
"revision": "7b0883c03e5edd34ef7bcf703194204299d7099f"
},
"chatito": {
"revision": "b4cbe9ab7672d5106e9550d8413835395a1be362"
},
"circom": {
"revision": "02150524228b1e6afef96949f2d6b7cc0aaf999e"
},
"clojure": {
"revision": "f4236d4da8aa92bc105d9c118746474c608e6af7"
},
"cmake": {
"revision": "fe48221d4d9842d916d66b5e71ab3c6307ec28b3"
},
"comment": {
"revision": "3555706cef8b98d3e4c7379d7260548ff03ad363"
},
"commonlisp": {
"revision": "32323509b3d9fe96607d151c2da2c9009eb13a2f"
},
"cooklang": {
"revision": "4ebe237c1cf64cf3826fc249e9ec0988fe07e58e"
},
"corn": {
"revision": "464654742cbfd3a3de560aba120998f1d5dfa844"
},
"cpon": {
"revision": "594289eadfec719198e560f9d7fd243c4db678d5"
},
"cpp": {
"revision": "e5cea0ec884c5c3d2d1e41a741a66ce13da4d945"
},
"css": {
"revision": "6e327db434fec0ee90f006697782e43ec855adf5"
},
"csv": {
"revision": "7eb7297823605392d2bbcc4c09b1cd18d6fa9529"
},
"cuda": {
"revision": "014628ae8d2df391b88ddb9fa0260fd97f770829"
},
"cue": {
"revision": "770737bcff2c4aa3f624d439e32b07dbb07102d3"
},
"cylc": {
"revision": "8b895c278f98d05e67997f5e3a43fb5531933023"
},
"d": {
"revision": "45e5f1e9d6de2c68591bc8e5ec662cf18e950b4a"
},
"dart": {
"revision": "80e23c07b64494f7e21090bb3450223ef0b192f4"
},
"desktop": {
"revision": "6d66eea37afa1d6bc1e25ef457113743df42416d"
},
"devicetree": {
"revision": "16f640f3c59117c9e749d581634afdb00e004f4c"
},
"dhall": {
"revision": "4a6c08abfb54827db4e722d6cdca81b093898988"
},
"diff": {
"revision": "e42b8def4f75633568f1aecfe01817bf15164928"
},
"disassembly": {
"revision": "0229c0211dba909c5d45129ac784a3f4d49c243a"
},
"djot": {
"revision": "eb31845d59b9ee8c1b2098e78e9ca72004bd1579"
},
"dockerfile": {
"revision": "971acdd908568b4531b0ba28a445bf0bb720aba5"
},
"dot": {
"revision": "9ab85550c896d8b294d9b9ca1e30698736f08cea"
},
"doxygen": {
"revision": "ccd998f378c3f9345ea4eeb223f56d7b84d16687"
},
"dtd": {
"revision": "0d9a8099c963ed53e183425c1b47fa2622c8eaf7"
},
"earthfile": {
"revision": "ae378d9d1306e9a967698516041f6f8803db5592"
},
"ebnf": {
"revision": "8e635b0b723c620774dfb8abf382a7f531894b40"
},
"editorconfig": {
"revision": "3f2b371537355f6e53cc3af37f79ba450efb5132"
},
"eds": {
"revision": "26d529e6cfecde391a03c21d1474eb51e0285805"
},
"eex": {
"revision": "f742f2fe327463335e8671a87c0b9b396905d1d1"
},
"elixir": {
"revision": "450a8194f5a66561135962cfc8d7545a27b61c4c"
},
"elm": {
"revision": "e34bdc5c512918628b05b48e633f711123204e45"
},
"elsa": {
"revision": "0a66b2b3f3c1915e67ad2ef9f7dbd2a84820d9d7"
},
"elvish": {
"revision": "5e7210d945425b77f82cbaebc5af4dd3e1ad40f5"
},
"embedded_template": {
"revision": "8495d106154741e6d35d37064f864758ece75de6"
},
"enforce": {
"revision": "aedd0bbab9dcc9caec9cc4e32bd303e86509522b"
},
"erlang": {
"revision": "416ca60d7d2a824c0d346163541153e230710780"
},
"facility": {
"revision": "e4bfd3e960de9f4b4648acb1c92e9b95b47d8cfb"
},
"faust": {
"revision": "f3b9274514b5f9bf6b0dd4a01c30f9cc15c58bc4"
},
"fennel": {
"revision": "cfbfa478dc2dbef267ee94ae4323d9c886f45e94"
},
"fidl": {
"revision": "0a8910f293268e27ff554357c229ba172b0eaed2"
},
"firrtl": {
"revision": "8503d3a0fe0f9e427863cb0055699ff2d29ae5f5"
},
"fish": {
"revision": "70640c0696abde32622afc43291a385681afbd32"
},
"foam": {
"revision": "f08bb76892b93e5b23c45ac3bd6b1eea5df323cc"
},
"forth": {
"revision": "90189238385cf636b9ee99ce548b9e5b5e569d48"
},
"fortran": {
"revision": "d738334e4a21866a1ab81fb3f27f9b0b2ad2e515"
},
"fsh": {
"revision": "fad2e175099a45efbc98f000cc196d3674cc45e0"
},
"fsharp": {
"revision": "02929f084726db969e5b916d144436f248146824"
},
"func": {
"revision": "f780ca55e65e7d7360d0229331763e16c452fc98"
},
"fusion": {
"revision": "19db2f47ba4c3a0f6238d4ae0e2abfca16e61dd6"
},
"gap": {
"revision": "7db79590d2f8b0e0246008ecfd569b4bfca587a9"
},
"gaptst": {
"revision": "69086d7627c03e1f4baf766bcef14c60d9e92331"
},
"gdscript": {
"revision": "48b49330888a4669b48619b211cc8da573827725"
},
"gdshader": {
"revision": "ffd9f958df13cae04593781d7d2562295a872455"
},
"git_config": {
"revision": "9c2a1b7894e6d9eedfe99805b829b4ecd871375e"
},
"git_rebase": {
"revision": "bff4b66b44b020d918d67e2828eada1974a966aa"
},
"gitattributes": {
"revision": "5425944fd61bf2b3bad2c17c2dc9f53172b0f01d"
},
"gitcommit": {
"revision": "a716678c0f00645fed1e6f1d0eb221481dbd6f6d"
},
"gitignore": {
"revision": "f4685bf11ac466dd278449bcfe5fd014e94aa504"
},
"gleam": {
"revision": "99ec4101504452c488b7c835fb65cfef75b090b7"
},
"glimmer": {
"revision": "da605af8c5999b43e6839b575eae5e6cafabb06f"
},
"glimmer_javascript": {
"revision": "5cc865a2a0a77cbfaf5062c8fcf2a9919bd54f87"
},
"glimmer_typescript": {
"revision": "12d98944c1d5077b957cbdb90d663a7c4d50118c"
},
"glsl": {
"revision": "24a6c8ef698e4480fecf8340d771fbcb5de8fbb4"
},
"gn": {
"revision": "bc06955bc1e3c9ff8e9b2b2a55b38b94da923c05"
},
"gnuplot": {
"revision": "8923c1e38b9634a688a6c0dce7c18c8ffb823e79"
},
"go": {
"revision": "5e73f476efafe5c768eda19bbe877f188ded6144"
},
"goctl": {
"revision": "49c43532689fe1f53e8b9e009d0521cab02c432b"
},
"godot_resource": {
"revision": "91c55fdf325a832659e59cdf4a02bfe8a423f14c"
},
"gomod": {
"revision": "6efb59652d30e0e9cd5f3b3a669afd6f1a926d3c"
},
"gosum": {
"revision": "e2ac513b2240c7ff1069ae33b2df29ce90777c11"
},
"gotmpl": {
"revision": "5f19a36bb1eebb30454e277b222b278ceafed0dd"
},
"gowork": {
"revision": "949a8a470559543857a62102c84700d291fc984c"
},
"gpg": {
"revision": "63e80cfe1302da9f9c7ee8d9df295f47d7d181bf"
},
"graphql": {
"revision": "5e66e961eee421786bdda8495ed1db045e06b5fe"
},
"gren": {
"revision": "06389ece5bc7344ed3931dc516bb609d8864dd2a"
},
"groovy": {
"revision": "86911590a8e46d71301c66468e5620d9faa5b6af"
},
"gstlaunch": {
"revision": "549aef253fd38a53995cda1bf55c501174372bf7"
},
"hack": {
"revision": "bc5b3a10d6d27e8220a113a9a7fe9bec0a1574b0"
},
"hare": {
"revision": "4af5d82cf9ec39f67cb1db5b7a9269d337406592"
},
"haskell": {
"revision": "0975ef72fc3c47b530309ca93937d7d143523628"
},
"haskell_persistent": {
"revision": "577259b4068b2c281c9ebf94c109bd50a74d5857"
},
"hcl": {
"revision": "de10d494dbd6b71cdf07a678fecbf404dbfe4398"
},
"heex": {
"revision": "008626a3fad379d17c81d5ed576edd9bd7a4fbf7"
},
"helm": {
"revision": "5f19a36bb1eebb30454e277b222b278ceafed0dd"
},
"hjson": {
"revision": "02fa3b79b3ff9a296066da6277adfc3f26cbc9e0"
},
"hlsl": {
"revision": "bab9111922d53d43668fabb61869bec51bbcb915"
},
"hlsplaylist": {
"revision": "3bfda9271e3adb08d35f47a2102fe957009e1c55"
},
"hocon": {
"revision": "c390f10519ae69fdb03b3e5764f5592fb6924bcc"
},
"hoon": {
"revision": "1545137aadcc63660c47db9ad98d02fa602655d0"
},
"html": {
"revision": "cbb91a0ff3621245e890d1c50cc811bffb77a26b"
},
"htmldjango": {
"revision": "ea71012d3fe14dd0b69f36be4f96bdfe9155ebae"
},
"http": {
"revision": "db8b4398de90b6d0b6c780aba96aaa2cd8e9202c"
},
"hurl": {
"revision": "ff07a42d9ec95443b5c1b57ed793414bf7b79be5"
},
"hyprlang": {
"revision": "d719158abe537b1916daaea6fa03287089f0b601"
},
"idl": {
"revision": "b14e7971cfbd64fa0ebcdeaa4dfbb3cb0bfabd7c"
},
"idris": {
"revision": "c56a25cf57c68ff929356db25505c1cc4c7820f6"
},
"ini": {
"revision": "32b31863f222bf22eb43b07d4e9be8017e36fb31"
},
"inko": {
"revision": "f58a87ac4dc6a7955c64c9e4408fbd693e804686"
},
"ipkg": {
"revision": "8d3e9782f2d091d0cd39c13bfb3068db0c675960"
},
"ispc": {
"revision": "9b2f9aec2106b94b4e099fe75e73ebd8ae707c04"
},
"janet_simple": {
"revision": "b08b402207fba0037d5152ce7c521351147f4388"
},
"java": {
"revision": "a7db5227ec40fcfe94489559d8c9bc7c8181e25a"
},
"javadoc": {
"revision": "330cc9cb4f33545f7bfce6c3b6aa77fe6db1b537"
},
"javascript": {
"revision": "6fbef40512dcd9f0a61ce03a4c9ae7597b36ab5c"
},
"jinja": {
"revision": "9af6ce9380fabd3d5b19d0254b8c8936e879c471"
},
"jinja_inline": {
"revision": "9af6ce9380fabd3d5b19d0254b8c8936e879c471"
},
"jq": {
"revision": "13990f530e8e6709b7978503da9bc8701d366791"
},
"jsdoc": {
"revision": "a417db5dbdd869fccb6a8b75ec04459e1d4ccd2c"
},
"json": {
"revision": "46aa487b3ade14b7b05ef92507fdaa3915a662a3"
},
"json5": {
"revision": "ab0ba8229d639ec4f3fa5f674c9133477f4b77bd"
},
"jsonc": {
"revision": "02b01653c8a1c198ae7287d566efa86a135b30d5"
},
"jsonnet": {
"revision": "ddd075f1939aed8147b7aa67f042eda3fce22790"
},
"julia": {
"revision": "12a3aede757bc7fbdfb1909507c7a6fddd31df37"
},
"just": {
"revision": "bb0c898a80644de438e6efe5d88d30bf092935cd"
},
"kcl": {
"revision": "b0b2eb38009e04035a6e266c7e11e541f3caab7c"
},
"kconfig": {
"revision": "9ac99fe4c0c27a35dc6f757cef534c646e944881"
},
"kdl": {
"revision": "b37e3d58e5c5cf8d739b315d6114e02d42e66664"
},
"kotlin": {
"revision": "c4ddea359a7ff4d92360b2efcd6cfce5dc25afe6"
},
"koto": {
"revision": "46770abba021e2ddd2c51d9fa3087fd1ab6b2aea"
},
"kusto": {
"revision": "8353a1296607d6ba33db7c7e312226e5fc83e8ce"
},
"lalrpop": {
"revision": "8d38e9755c05d37df8a24dadb0fc64f6588ac188"
},
"latex": {
"revision": "7b06f6ed394308e7407a1703d2724128c45fc9d7"
},
"ledger": {
"revision": "d313153eef68c557ba4538b20de2d0e92f3ef6f8"
},
"leo": {
"revision": "6bc5564917edacd070afc4d33cf5e2e677831ea9"
},
"linkerscript": {
"revision": "f99011a3554213b654985a4b0a65b3b032ec4621"
},
"liquid": {
"revision": "d269f4d52cd08f6cbc6636ee23cc30a9f6c32e42"
},
"liquidsoap": {
"revision": "8e51fa63ddb93ac179d4e34a311d3d3f03780b42"
},
"llvm": {
"revision": "c14cb839003348692158b845db9edda201374548"
},
"lua": {
"revision": "db16e76558122e834ee214c8dc755b4a3edc82a9"
},
"luadoc": {
"revision": "873612aadd3f684dd4e631bdf42ea8990c57634e"
},
"luap": {
"revision": "c134aaec6acf4fa95fe4aa0dc9aba3eacdbbe55a"
},
"luau": {
"revision": "a8914d6c1fc5131f8e1c13f769fa704c9f5eb02f"
},
"m68k": {
"revision": "e128454c2210c0e0c10b68fe45ddb8fee80182a3"
},
"make": {
"revision": "a4b9187417d6be349ee5fd4b6e77b4172c6827dd"
},
"markdown": {
"revision": "413285231ce8fa8b11e7074bbe265b48aa7277f9"
},
"markdown_inline": {
"revision": "413285231ce8fa8b11e7074bbe265b48aa7277f9"
},
"matlab": {
"revision": "bbf1b3f0bd7417c1efb8958fe95be3d0d540207a"
},
"menhir": {
"revision": "be8866a6bcc2b563ab0de895af69daeffa88fe70"
},
"mermaid": {
"revision": "90ae195b31933ceb9d079abfa8a3ad0a36fee4cc"
},
"meson": {
"revision": "a56af662e8540412fed5e40cc20435b2b9a20502"
},
"mlir": {
"revision": "922cbb97f3d20044e6b4362b3d7af5e530ed8f34"
},
"muttrc": {
"revision": "173b0ab53a9c07962c9777189c4c70e90f1c1837"
},
"nasm": {
"revision": "d1b3638d017f2a8585e26dcfc66fe1df94185e30"
},
"nginx": {
"revision": "989da760be05a3334af3ec88705cbf57e6a9c41d"
},
"nickel": {
"revision": "25464b33522c3f609fa512aa9651707c0b66d48b"
},
"nim": {
"revision": "897e5d346f0b59ed62b517cfb0f1a845ad8f0ab7"
},
"nim_format_string": {
"revision": "d45f75022d147cda056e98bfba68222c9c8eca3a"
},
"ninja": {
"revision": "0a95cfdc0745b6ae82f60d3a339b37f19b7b9267"
},
"nix": {
"revision": "cfc53fd287d23ab7281440a8526c73542984669b"
},
"norg": {
"revision": "d89d95af13d409f30a6c7676387bde311ec4a2c8"
},
"nqc": {
"revision": "14e6da1627aaef21d2b2aa0c37d04269766dcc1d"
},
"nu": {
"revision": "d5c71a10b4d1b02e38967b05f8de70e847448dd1"
},
"objc": {
"revision": "181a81b8f23a2d593e7ab4259981f50122909fda"
},
"objdump": {
"revision": "28d3b2e25a0b1881d1b47ed1924ca276c7003d45"
},
"ocaml": {
"revision": "91708deb10cb4fe68ab3c50891426b9967dbf35a"
},
"ocaml_interface": {
"revision": "91708deb10cb4fe68ab3c50891426b9967dbf35a"
},
"ocamllex": {
"revision": "c5cf996c23e38a1537069fbe2d4bb83a75fc7b2f"
},
"odin": {
"revision": "d2ca8efb4487e156a60d5bd6db2598b872629403"
},
"pascal": {
"revision": "78426d96bde7114af979e314283e45d087603428"
},
"passwd": {
"revision": "20239395eacdc2e0923a7e5683ad3605aee7b716"
},
"pem": {
"revision": "1d16b8e063fdf4385e389096c4bc4999eaaef05f"
},
"perl": {
"revision": "ecd90bd8b381bcc7219fed4fe351903630e761c6"
},
"php": {
"revision": "576a56fa7f8b68c91524cdd211eb2ffc43e7bb11"
},
"php_only": {
"revision": "576a56fa7f8b68c91524cdd211eb2ffc43e7bb11"
},
"phpdoc": {
"revision": "fe3202e468bc17332bec8969f2b50ff1f1da3a46"
},
"pioasm": {
"revision": "afece58efdb30440bddd151ef1347fa8d6f744a9"
},
"po": {
"revision": "bd860a0f57f697162bf28e576674be9c1500db5e"
},
"pod": {
"revision": "0bf8387987c21bf2f8ed41d2575a8f22b139687f"
},
"poe_filter": {
"revision": "2902dc45439125b9386812c1089a8e9b5f71c4ab"
},
"pony": {
"revision": "73ff874ae4c9e9b45462673cbc0a1e350e2522a7"
},
"powershell": {
"revision": "66d5e61126989c0aca57ff77d19b2064919b51e1"
},
"printf": {
"revision": "df6b69967db7d74ab338a86a9ab45c0966c5ee3c"
},
"prisma": {
"revision": "73f39a6d5401cfdcd143951e499336cf5ab2ffaa"
},
"problog": {
"revision": "d8d415f6a1cf80ca138524bcc395810b176d40fa"
},
"prolog": {
"revision": "d8d415f6a1cf80ca138524bcc395810b176d40fa"
},
"promql": {
"revision": "77625d78eebc3ffc44d114a07b2f348dff3061b0"
},
"properties": {
"revision": "579b62f5ad8d96c2bb331f07d1408c92767531d9"
},
"proto": {
"revision": "e9f6b43f6844bd2189b50a422d4e2094313f6aa3"
},
"prql": {
"revision": "09e158cd3650581c0af4c49c2e5b10c4834c8646"
},
"psv": {
"revision": "7eb7297823605392d2bbcc4c09b1cd18d6fa9529"
},
"pug": {
"revision": "13e9195370172c86a8b88184cc358b23b677cc46"
},
"puppet": {
"revision": "15f192929b7d317f5914de2b4accd37b349182a6"
},
"purescript": {
"revision": "daf9b3e2be18b0b2996a1281f7783e0d041d8b80"
},
"pymanifest": {
"revision": "be062582956165019d3253794b4d712f66dfeaaa"
},
"python": {
"revision": "710796b8b877a970297106e5bbc8e2afa47f86ec"
},
"ql": {
"revision": "1fd627a4e8bff8c24c11987474bd33112bead857"
},
"qmldir": {
"revision": "6b2b5e41734bd6f07ea4c36ac20fb6f14061c841"
},
"qmljs": {
"revision": "0889da4632bba3ec6f39ef4102625654890c15c1"
},
"query": {
"revision": "930202c2a80965a7a9ca018b5b2a08b25dfa7f12"
},
"r": {
"revision": "a0d3e3307489c3ca54da8c7b5b4e0c5f5fd6953a"
},
"racket": {
"revision": "5b211bf93021d1c45f39aa96898be9f794f087e4"
},
"ralph": {
"revision": "f6d81bf7a4599c77388035439cf5801cd461ff77"
},
"rasi": {
"revision": "6c9bbcfdf5f0f553d9ebc01750a3aa247a37b8aa"
},
"razor": {
"revision": "fe46ce5ea7d844e53d59bc96f2175d33691c61c5"
},
"rbs": {
"revision": "de893b166476205b09e79cd3689f95831269579a"
},
"re2c": {
"revision": "c18a3c2f4b6665e35b7e50d6048ea3cff770c572"
},
"readline": {
"revision": "74addc90fc539d31d413c0c7cf7581997a7fa46e"
},
"regex": {
"revision": "b638d29335ef41215b86732dd51be34c701ef683"
},
"rego": {
"revision": "20b5a5958c837bc9f74b231022a68a594a313f6d"
},
"requirements": {
"revision": "728910099ddea7f1f94ea95a35a70d1ea76a1639"
},
"rescript": {
"revision": "4606cd81c4c31d1d02390fee530858323410a74c"
},
"rnoweb": {
"revision": "1a74dc0ed731ad07db39f063e2c5a6fe528cae7f"
},
"robot": {
"revision": "17c2300e91fc9da4ba14c16558bf4292941dc074"
},
"robots": {
"revision": "8e3a4205b76236bb6dbebdbee5afc262ce38bb62"
},
"roc": {
"revision": "0b1afe88161cbd81f5ddea1bb4fa786314ed49a7"
},
"ron": {
"revision": "78938553b93075e638035f624973083451b29055"
},
"rst": {
"revision": "4e562e1598b95b93db4f3f64fe40ddefbc677a15"
},
"ruby": {
"revision": "89bd7a8e5450cb6a942418a619d30469f259e5d6"
},
"runescript": {
"revision": "cf85bbd5da0c5ad243301d889c7f84d790a4cae4"
},
"rust": {
"revision": "e86119bdb4968b9799f6a014ca2401c178d54b5f"
},
"scala": {
"revision": "c1189954df854977c3a52003ca8a247c5f4729ba"
},
"scfg": {
"revision": "2f3709e7656fa2c443f92041c91a9f843f8cd625"
},
"scheme": {
"revision": "63e25a4a84142ae7ee0ee01fe3a32c985ca16745"
},
"scss": {
"revision": "c478c6868648eff49eb04a4df90d703dc45b312a"
},
"sflog": {
"revision": "3597575a429766dd7ecce9f5bb97f6fec4419d5d"
},
"slang": {
"revision": "3ed23c04a412a0559162d9cadf96dfff7cb36079"
},
"slim": {
"revision": "546e3aa1af8a3b355c7734efccd9a759ffc0b43a"
},
"slint": {
"revision": "f11da7e62051ba8b9d4faa299c26de8aeedfc1cd"
},
"smali": {
"revision": "fdfa6a1febc43c7467aa7e937b87b607956f2346"
},
"smithy": {
"revision": "fa898ac0885d1da9a253695c3e0e91f5efc587cd"
},
"snakemake": {
"revision": "f36c1587624d6d84376c82a357c20fc319cbf02c"
},
"solidity": {
"revision": "d38dcd0b58b223c43e3f9265914fb3167dc624c6"
},
"soql": {
"revision": "3597575a429766dd7ecce9f5bb97f6fec4419d5d"
},
"sosl": {
"revision": "3597575a429766dd7ecce9f5bb97f6fec4419d5d"
},
"sourcepawn": {
"revision": "f2af8d0dc14c6790130cceb2a20027eb41a8297c"
},
"sparql": {
"revision": "d853661ca680d8ff7f8d800182d5782b61d0dd58"
},
"sql": {
"revision": "b9d109588d5b5ed986c857464830c2f0bef53f18"
},
"squirrel": {
"revision": "072c969749e66f000dba35a33c387650e203e96e"
},
"ssh_config": {
"revision": "0dd3c7e9f301758f6c69a6efde43d3048deb4d8a"
},
"starlark": {
"revision": "a453dbf3ba433db0e5ec621a38a7e59d72e4dc69"
},
"strace": {
"revision": "d819cdd5dbe455bd3c859193633c8d91c0df7c36"
},
"styled": {
"revision": "319cdcaa0346ba6db668a222d938e5c3569e2a51"
},
"supercollider": {
"revision": "1a8ee0da9a4f2df5a8a22f4d637ac863623a78a7"
},
"superhtml": {
"revision": "16887e9fa3122c36a3d4942470e33c1c282fe859"
},
"surface": {
"revision": "f4586b35ac8548667a9aaa4eae44456c1f43d032"
},
"svelte": {
"revision": "ae5199db47757f785e43a14b332118a5474de1a2"
},
"sway": {
"revision": "395006713db3bbb90d267ebdfcbf1881b399b05c"
},
"swift": {
"revision": "aca5a52aa3cab858944d3c02701ccf5b2d8fd0f9"
},
"sxhkdrc": {
"revision": "440d5f913d9465c9c776a1bd92334d32febcf065"
},
"systemtap": {
"revision": "f2b378a9af0b7e1192cff67a5fb45508c927205d"
},
"t32": {
"revision": "e5a12f798f056049642aa03fbb83786e3a5b95d4"
},
"tablegen": {
"revision": "b1170880c61355aaf38fc06f4af7d3c55abdabc4"
},
"tact": {
"revision": "47af20264abbd24ea282ded0f8ee9cad3cf3bf2f"
},
"tcl": {
"revision": "f15e711167661d1ba541d4f62b9dbfc4ce61ec56"
},
"teal": {
"revision": "3db655924b2ff1c54fdf6371b5425ea6b5dccefe"
},
"templ": {
"revision": "def9849184de71a797c4e2b2837df85abeccf92c"
},
"tera": {
"revision": "25a7c617192253bddfa65e378975d8c476419010"
},
"terraform": {
"revision": "de10d494dbd6b71cdf07a678fecbf404dbfe4398"
},
"textproto": {
"revision": "568471b80fd8793d37ed01865d8c2208a9fefd1b"
},
"thrift": {
"revision": "68fd0d80943a828d9e6f49c58a74be1e9ca142cf"
},
"tiger": {
"revision": "4a77b2d7a004587646bddc4e854779044b6db459"
},
"tlaplus": {
"revision": "4ba91b07b97741a67f61221d0d50e6d962e4987e"
},
"tmux": {
"revision": "0252ecd080016e45e6305ef1a943388f5ae2f4b4"
},
"todotxt": {
"revision": "3937c5cd105ec4127448651a21aef45f52d19609"
},
"toml": {
"revision": "64b56832c2cffe41758f28e05c756a3a98d16f41"
},
"tsv": {
"revision": "7eb7297823605392d2bbcc4c09b1cd18d6fa9529"
},
"tsx": {
"revision": "75b3874edb2dc714fb1fd77a32013d0f8699989f"
},
"turtle": {
"revision": "7f789ea7ef765080f71a298fc96b7c957fa24422"
},
"twig": {
"revision": "085648e01d1422163a1702a44e72303b4e2a0bd1"
},
"typescript": {
"revision": "75b3874edb2dc714fb1fd77a32013d0f8699989f"
},
"typespec": {
"revision": "42fb163442ef2691b9b720fb4e4e846809415d18"
},
"typoscript": {
"revision": "5d8fde870b0ded1f429ba5bb249a9d9f8589ff5f"
},
"typst": {
"revision": "46cf4ded12ee974a70bf8457263b67ad7ee0379d"
},
"udev": {
"revision": "18a1d183c4c0cc40438bae2ebf8191aaf2dee8dc"
},
"ungrammar": {
"revision": "debd26fed283d80456ebafa33a06957b0c52e451"
},
"unison": {
"revision": "169e7f748a540ec360c0cb086b448faad012caa4"
},
"usd": {
"revision": "4e0875f724d94d0c2ff36f9b8cb0b12f8b20d216"
},
"uxntal": {
"revision": "ad9b638b914095320de85d59c49ab271603af048"
},
"v": {
"revision": "26c2c4c2b3fb4f7a07ae78d298b36998b7ffa956"
},
"vala": {
"revision": "97e6db3c8c73b15a9541a458d8e797a07f588ef4"
},
"vento": {
"revision": "3b32474bc29584ea214e4e84b47102408263fe0e"
},
"verilog": {
"revision": "15fbf73dafaffc89050d247857beb27500ea30e8"
},
"vhdl": {
"revision": "35ed277d3e98836796bc764010dc3fb800d14ee4"
},
"vhs": {
"revision": "0c6fae9d2cfc5b217bfd1fe84a7678f5917116db"
},
"vim": {
"revision": "11b688a1f0e97c0c4e3dbabf4a38016335f4d237"
},
"vimdoc": {
"revision": "2694c3d27e2ca98a0ccde72f33887394300d524e"
},
"vrl": {
"revision": "274b3ce63f72aa8ffea18e7fc280d3062d28f0ba"
},
"vue": {
"revision": "22bdfa6c9fc0f5ffa44c6e938ec46869ac8a99ff"
},
"wgsl": {
"revision": "40259f3c77ea856841a4e0c4c807705f3e4a2b65"
},
"wgsl_bevy": {
"revision": "47c1818d245a6156a488c4c4d06e9336714bae9b"
},
"wing": {
"revision": "76e0c25844a66ebc6e866d690fcc5f4e90698947"
},
"wit": {
"revision": "81490b4e74c792369e005f72b0d46fe082d3fed2"
},
"xcompose": {
"revision": "fff3e72242aa110ebba6441946ea4d12d200fa68"
},
"xml": {
"revision": "0d9a8099c963ed53e183425c1b47fa2622c8eaf7"
},
"xresources": {
"revision": "d0f9dc7cec4dc15fc6f9d556bb4e9dd5050328a6"
},
"yaml": {
"revision": "1805917414a9a8ba2473717fd69447277a175fae"
},
"yang": {
"revision": "2c0e6be8dd4dcb961c345fa35c309ad4f5bd3502"
},
"yuck": {
"revision": "e877f6ade4b77d5ef8787075141053631ba12318"
},
"zathurarc": {
"revision": "0554b4a5d313244b7fc000cbb41c04afae4f4e31"
},
"zig": {
"revision": "b670c8df85a1568f498aa5c8cae42f51a90473c0"
},
"ziggy": {
"revision": "8a29017169f43dc2c3526817e98142eb9a335087"
},
"ziggy_schema": {
"revision": "8a29017169f43dc2c3526817e98142eb9a335087"
}
}

View file

@ -1,22 +0,0 @@
local install = require "nvim-treesitter.install"
local utils = require "nvim-treesitter.utils"
local info = require "nvim-treesitter.info"
local configs = require "nvim-treesitter.configs"
local statusline = require "nvim-treesitter.statusline"
-- Registers all query predicates
require "nvim-treesitter.query_predicates"
local M = {}
function M.setup()
utils.setup_commands("install", install.commands)
utils.setup_commands("info", info.commands)
utils.setup_commands("configs", configs.commands)
configs.init()
end
M.define_modules = configs.define_modules
M.statusline = statusline.statusline
return M

View file

@ -0,0 +1,47 @@
---@meta
error('Cannot require a meta file')
---@class InstallInfo
---
---URL of parser repo (Github)
---@field url string
---
---Commit hash of parser to download (compatible with queries)
---@field revision string
---
---Branch of parser repo to download (if not default branch)
---@field branch? string
---
---Location of `grammar.js` in repo (if not at root, e.g., in a monorepo)
---@field location? string
---
---Repo does not contain a `parser.c`; must be generated from grammar first
---@field generate? boolean
---
---Generate parser from `grammar.json` instead of `grammar.js` (default true)
---@field generate_from_json? boolean
---
---Parser repo is a local directory; overrides `url`, `revision`, and `branch`
---@field path? string
---
---Directory with queries to be installed
---@field queries? string
---@class ParserInfo
---
---Information necessary to build and install the parser (empty for query-only language)
---@field install_info? InstallInfo
---
---List of Github users maintaining the queries for Neovim
---@field maintainers? string[]
---
---List of other languages to install (e.g., if queries inherit from them)
---@field requires? string[]
---
---Language support tier, maps to "stable", "unstable", "unmaintained", "unsupported"
---@field tier integer
---
---Explanatory footnote text to add in SUPPORTED_LANGUAGES.md
---@field readme_note? string
---@alias nvim-ts.parsers table<string,ParserInfo>

736
lua/nvim-treesitter/async.lua vendored Normal file
View file

@ -0,0 +1,736 @@
---@meta nvim-treesitter.async vendored file, don't diagnose
local pcall = copcall or pcall
--- @param ... any
--- @return {[integer]: any, n: integer}
local function pack_len(...)
return { n = select('#', ...), ... }
end
--- like unpack() but use the length set by F.pack_len if present
--- @param t? { [integer]: any, n?: integer }
--- @param first? integer
--- @return ...any
local function unpack_len(t, first)
if t then
return unpack(t, first or 1, t.n or table.maxn(t))
end
end
--- @class async
local M = {}
--- Weak table to keep track of running tasks
--- @type table<thread,async.Task?>
local threads = setmetatable({}, { __mode = 'k' })
--- @return async.Task?
local function running()
local task = threads[coroutine.running()]
if task and not (task:_completed() or task._closing) then
return task
end
end
--- Base class for async tasks. Async functions should return a subclass of
--- this. This is designed specifically to be a base class of uv_handle_t
--- @class async.Handle
--- @field close fun(self: async.Handle, callback?: fun())
--- @field is_closing? fun(self: async.Handle): boolean
--- @alias async.CallbackFn fun(...: any): async.Handle?
--- @class async.Task : async.Handle
--- @field package _callbacks table<integer,fun(err?: any, ...: any)>
--- @field package _callback_pos integer
--- @field private _thread thread
---
--- Tasks can call other async functions (task of callback functions)
--- when we are waiting on a child, we store the handle to it here so we can
--- cancel it.
--- @field private _current_child? async.Handle
---
--- Error result of the task is an error occurs.
--- Must use `await` to get the result.
--- @field private _err? any
---
--- Result of the task.
--- Must use `await` to get the result.
--- @field private _result? any[]
local Task = {}
Task.__index = Task
--- @private
--- @param func function
--- @return async.Task
function Task._new(func)
local thread = coroutine.create(func)
local self = setmetatable({
_closing = false,
_thread = thread,
_callbacks = {},
_callback_pos = 1,
}, Task)
threads[thread] = self
return self
end
--- @param callback fun(err?: any, ...: any)
function Task:await(callback)
if self._closing then
callback('closing')
elseif self:_completed() then -- TODO(lewis6991): test
-- Already finished or closed
callback(self._err, unpack_len(self._result))
else
self._callbacks[self._callback_pos] = callback
self._callback_pos = self._callback_pos + 1
end
end
--- @package
function Task:_completed()
return (self._err or self._result) ~= nil
end
-- Use max 32-bit signed int value to avoid overflow on 32-bit systems.
-- Do not use `math.huge` as it is not interpreted as a positive integer on all
-- platforms.
local MAX_TIMEOUT = 2 ^ 31 - 1
--- Synchronously wait (protected) for a task to finish (blocking)
---
--- If an error is returned, `Task:traceback()` can be used to get the
--- stack trace of the error.
---
--- Example:
--- ```lua
---
--- local ok, err_or_result = task:pwait(10)
---
--- if not ok then
--- error(task:traceback(err_or_result))
--- end
---
--- local _, result = assert(task:pwait(10))
--- ```
---
--- Can be called if a task is closing.
--- @param timeout? integer
--- @return boolean status
--- @return any ... result or error
function Task:pwait(timeout)
local done = vim.wait(timeout or MAX_TIMEOUT, function()
-- Note we use self:_completed() instead of self:await() to avoid creating a
-- callback. This avoids having to cleanup/unregister any callback in the
-- case of a timeout.
return self:_completed()
end)
if not done then
return false, 'timeout'
elseif self._err then
return false, self._err
else
return true, unpack_len(self._result)
end
end
--- Synchronously wait for a task to finish (blocking)
---
--- Example:
--- ```lua
--- local result = task:wait(10) -- wait for 10ms or else error
---
--- local result = task:wait() -- wait indefinitely
--- ```
--- @param timeout? integer Timeout in milliseconds
--- @return any ... result
function Task:wait(timeout)
local res = pack_len(self:pwait(timeout))
local stat = res[1]
if not stat then
error(self:traceback(res[2]))
end
return unpack_len(res, 2)
end
--- @private
--- @param msg? string
--- @param _lvl? integer
--- @return string
function Task:_traceback(msg, _lvl)
_lvl = _lvl or 0
local thread = ('[%s] '):format(self._thread)
local child = self._current_child
if getmetatable(child) == Task then
--- @cast child async.Task
msg = child:_traceback(msg, _lvl + 1)
end
local tblvl = getmetatable(child) == Task and 2 or nil
msg = (msg or '') .. debug.traceback(self._thread, '', tblvl):gsub('\n\t', '\n\t' .. thread)
if _lvl == 0 then
--- @type string
msg = msg
:gsub('\nstack traceback:\n', '\nSTACK TRACEBACK:\n', 1)
:gsub('\nstack traceback:\n', '\n')
:gsub('\nSTACK TRACEBACK:\n', '\nstack traceback:\n', 1)
end
return msg
end
--- Get the traceback of a task when it is not active.
--- Will also get the traceback of nested tasks.
---
--- @param msg? string
--- @return string
function Task:traceback(msg)
return self:_traceback(msg)
end
--- If a task completes with an error, raise the error
function Task:raise_on_error()
self:await(function(err)
if err then
error(self:_traceback(err), 0)
end
end)
return self
end
--- @private
--- @param err? any
--- @param result? {[integer]: any, n: integer}
function Task:_finish(err, result)
self._current_child = nil
self._err = err
self._result = result
threads[self._thread] = nil
local errs = {} --- @type string[]
for _, cb in pairs(self._callbacks) do
--- @type boolean, string
local ok, cb_err = pcall(cb, err, unpack_len(result))
if not ok then
errs[#errs + 1] = cb_err
end
end
if #errs > 0 then
error(table.concat(errs, '\n'), 0)
end
end
--- @return boolean
function Task:is_closing()
return self._closing
end
--- Close the task and all its children.
--- If callback is provided it will run asynchronously,
--- else it will run synchronously.
---
--- @param callback? fun()
function Task:close(callback)
if self:_completed() then
if callback then
callback()
end
return
end
if self._closing then
return
end
self._closing = true
if callback then -- async
if self._current_child then
self._current_child:close(function()
self:_finish('closed')
callback()
end)
else
self:_finish('closed')
callback()
end
else -- sync
if self._current_child then
self._current_child:close(function()
self:_finish('closed')
end)
else
self:_finish('closed')
end
vim.wait(0, function()
return self:_completed()
end)
end
end
--- @param obj any
--- @return boolean
local function is_async_handle(obj)
local ty = type(obj)
return (ty == 'table' or ty == 'userdata') and vim.is_callable(obj.close)
end
--- @param ... any
function Task:_resume(...)
--- @type [boolean, string|async.CallbackFn]
local ret = pack_len(coroutine.resume(self._thread, ...))
local stat = ret[1]
if not stat then
-- Coroutine had error
self:_finish(ret[2])
elseif coroutine.status(self._thread) == 'dead' then
-- Coroutine finished
local result = pack_len(unpack_len(ret, 2))
self:_finish(nil, result)
else
local fn = ret[2]
--- @cast fn -string
-- TODO(lewis6991): refine error handler to be more specific
local ok, r
ok, r = pcall(fn, function(...)
if is_async_handle(r) then
--- @cast r async.Handle
-- We must close children before we resume to ensure
-- all resources are collected.
local args = pack_len(...)
r:close(function()
self:_resume(unpack_len(args))
end)
else
self:_resume(...)
end
end)
if not ok then
self:_finish(r)
elseif is_async_handle(r) then
self._current_child = r
end
end
end
--- @return 'running'|'suspended'|'normal'|'dead'?
function Task:status()
return coroutine.status(self._thread)
end
--- Run a function in an async context, asynchronously.
---
--- Examples:
--- ```lua
--- -- The two below blocks are equivalent:
---
--- -- Run a uv function and wait for it
--- local stat = async.arun(function()
--- return async.await(2, vim.uv.fs_stat, 'foo.txt')
--- end):wait()
---
--- -- Since uv functions have sync versions. You can just do:
--- local stat = vim.fs_stat('foo.txt')
--- ```
--- @generic T, R
--- @param func async fun(...: T...): R...
--- @param ... T...
--- @return async.Task
function M.arun(func, ...)
local task = Task._new(func)
task:_resume(...)
return task
end
--- @alias async.TaskFun<T, R> fun(...: T...): async.Task
--- @generic T, R
--- @class async._TaskFun<T, R>
--- @field package _fun async fun(...: T...): R...
--- @operator call(...: T...): async.Task
local TaskFun = {}
TaskFun.__index = TaskFun
--- @generic T, R
--- @param self async._TaskFun<T, R>
--- @param ... T...
--- @return async.Task
function TaskFun:__call(...)
return M.arun(self._fun, ...)
end
--- Create an async function
--- @generic T, R
--- @param fun async fun(...: T...): R...
--- @return async.TaskFun<T, R>
function M.async(fun)
return setmetatable({ _fun = fun }, TaskFun)
end
--- Returns the status of a tasks thread.
---
--- @param task? async.Task
--- @return 'running'|'suspended'|'normal'|'dead'?
function M.status(task)
task = task or running()
if task then
assert(getmetatable(task) == Task, 'Expected Task')
return task:status()
end
end
--- @async
--- @generic R1, R2, R3, R4
--- @param fun fun(callback: fun(r1: R1, r2: R2, r3: R3, r4: R4)): any?
--- @return R1, R2, R3, R4
local function yield(fun)
assert(type(fun) == 'function', 'Expected function')
return coroutine.yield(fun)
end
--- @async
--- @param task async.Task
--- @return any ...
local function await_task(task)
--- @param callback fun(err?: string, ...: any)
--- @return function
local res = pack_len(yield(function(callback)
task:await(callback)
return task
end))
local err = res[1]
if err then
-- TODO(lewis6991): what is the correct level to pass?
error(err, 0)
end
return unpack_len(res, 2)
end
--- Asynchronous blocking wait
--- @param argc integer
--- @param fun async.CallbackFn
--- @param ... any func arguments
--- @return any ...
local function await_cbfun(argc, fun, ...)
local args = pack_len(...)
--- @param callback fun(...:any)
--- @return any?
return yield(function(callback)
args[argc] = callback
args.n = math.max(args.n, argc)
return fun(unpack_len(args))
end)
end
--- @generic T, R
--- @param taskfun async.TaskFun<T, R>
--- @param ... T...
--- @return R...
local function await_taskfun(taskfun, ...)
return taskfun._fun(...)
end
--- Asynchronous blocking wait
---
--- Example:
--- ```lua
--- local task = async.arun(function()
--- return 1, 'a'
--- end)
---
--- local task_fun = async.async(function(arg)
--- return 2, 'b', arg
--- end)
---
--- async.arun(function()
--- do -- await a callback function
--- async.await(1, vim.schedule)
--- end
---
--- do -- await a task (new async context)
--- local n, s = async.await(task)
--- assert(n == 1 and s == 'a')
--- end
---
--- do -- await a started task function (new async context)
--- local n, s, arg = async.await(task_fun('A'))
--- assert(n == 2)
--- assert(s == 'b')
--- assert(args == 'A')
--- end
---
--- do -- await a task function (re-using the current async context)
--- local n, s, arg = async.await(task_fun, 'B')
--- assert(n == 2)
--- assert(s == 'b')
--- assert(args == 'B')
--- end
--- end)
--- ```
--- @async
--- @overload fun(argc: integer, func: async.CallbackFn, ...:any): any ...
--- @overload fun(task: async.Task): any ...
--- @overload fun(taskfun: async.TaskFun): any ...
function M.await(...)
assert(running(), 'Not in async context')
local arg1 = select(1, ...)
if type(arg1) == 'number' then
return await_cbfun(...)
elseif getmetatable(arg1) == Task then
return await_task(...)
elseif getmetatable(arg1) == TaskFun then
return await_taskfun(...)
end
error('Invalid arguments, expected Task or (argc, func) got: ' .. type(arg1), 2)
end
--- Creates an async function with a callback style function.
---
--- Example:
---
--- ```lua
--- --- Note the callback argument is not present in the return function
--- --- @type fun(timeout: integer)
--- local sleep = async.awrap(2, function(timeout, callback)
--- local timer = vim.uv.new_timer()
--- timer:start(timeout * 1000, 0, callback)
--- -- uv_timer_t provides a close method so timer will be
--- -- cleaned up when this function finishes
--- return timer
--- end)
---
--- async.arun(function()
--- print('hello')
--- sleep(2)
--- print('world')
--- end)
--- ```
---
--- local atimer = async.awrap(
--- @param argc integer
--- @param func async.CallbackFn
--- @return async function
function M.awrap(argc, func)
assert(type(argc) == 'number')
assert(type(func) == 'function')
--- @async
return function(...)
return M.await(argc, func, ...)
end
end
if vim.schedule then
--- An async function that when called will yield to the Neovim scheduler to be
--- able to call the API.
M.schedule = M.awrap(1, vim.schedule)
end
--- Create a function that runs a function when it is garbage collected.
--- @generic F
--- @param f F
--- @param gc fun()
--- @return F
local function gc_fun(f, gc)
local proxy = newproxy(true)
local proxy_mt = getmetatable(proxy)
proxy_mt.__gc = gc
proxy_mt.__call = function(_, ...)
return f(...)
end
return proxy
end
--- @param task_cbs table<async.Task,function>
local function gc_cbs(task_cbs)
for task, tcb in pairs(task_cbs) do
for j, cb in pairs(task._callbacks) do
if cb == tcb then
task._callbacks[j] = nil
break
end
end
end
end
--- @async
--- Example:
--- ```lua
--- local task1 = async.arun(function()
--- return 1, 'a'
--- end)
---
--- local task2 = async.arun(function()
--- return 1, 'a'
--- end)
---
--- local task3 = async.arun(function()
--- error('task3 error')
--- end)
---
--- async.arun(function()
--- for i, err, r1, r2 in async.iter({task1, task2, task3})
--- print(i, err, r1, r2)
--- end
--- end)
--- ```
---
--- Prints:
--- ```
--- 1 nil 1 'a'
--- 2 nil 2 'b'
--- 3 'task3 error' nil nil
--- ```
---
--- @param tasks async.Task[]
--- @return fun(): (integer?, any?, ...)
function M.iter(tasks)
assert(running(), 'Not in async context')
local results = {} --- @type [integer, any, ...][]
-- Iter blocks in an async context so only one waiter is needed
local waiter = nil
local task_cbs = {} --- @type table<async.Task,function>
local remaining = #tasks
--- If can_gc_cbs is true, then the iterator function has been garbage
--- collected and means any awaiters can also be garbage collected. The
--- only time we can't do this is if with the special case when iter() is
--- called anonymously (`local i = async.iter(tasks)()`), so we should not
--- garbage collect the callbacks until at least one awaiter is called.
local can_gc_cbs = false
for i, task in ipairs(tasks) do
local function cb(err, ...)
if can_gc_cbs == true then
gc_cbs(task_cbs)
end
local callback = waiter
-- Clear waiter before calling it
waiter = nil
remaining = remaining - 1
if callback then
-- Iterator is waiting, yield to it
callback(i, err, ...)
else
-- Task finished before Iterator was called. Store results.
table.insert(results, pack_len(i, err, ...))
end
end
task_cbs[task] = cb
task:await(cb)
end
return gc_fun(
M.awrap(1, function(callback)
if next(results) then
local res = table.remove(results, 1)
callback(unpack_len(res))
elseif remaining == 0 then
callback() -- finish
else
assert(not waiter, 'internal error: waiter already set')
waiter = callback
end
end),
function()
-- Don't gc callbacks just yet. Wait until at least one of them is called.
can_gc_cbs = true
end
)
end
do -- join()
--- @param results table<integer,table>
--- @param i integer
--- @param ... any
--- @return boolean
local function collect(results, i, ...)
if i then
results[i] = pack_len(...)
end
return i ~= nil
end
--- @param iter fun(): ...
--- @return table<integer,table>
local function drain_iter(iter)
local results = {} --- @type table<integer,table>
while collect(results, iter()) do
end
return results
end
--- @async
--- Wait for all tasks to finish and return their results.
---
--- Example:
--- ```lua
--- local task1 = async.arun(function()
--- return 1, 'a'
--- end)
---
--- local task2 = async.arun(function()
--- return 1, 'a'
--- end)
---
--- local task3 = async.arun(function()
--- error('task3 error')
--- end)
---
--- async.arun(function()
--- local results = async.join({task1, task2, task3})
--- print(vim.inspect(results))
--- end)
--- ```
---
--- Prints:
--- ```
--- {
--- [1] = { nil, 1, 'a' },
--- [2] = { nil, 2, 'b' },
--- [3] = { 'task2 error' },
--- }
--- ```
--- @param tasks async.Task[]
--- @return table<integer,[any?,...?]>
function M.join(tasks)
assert(running(), 'Not in async context')
return drain_iter(M.iter(tasks))
end
--- @async
--- @param tasks async.Task[]
--- @return integer?, any?, ...?
function M.joinany(tasks)
return M.iter(tasks)()
end
end
return M

View file

@ -1,71 +0,0 @@
local api = vim.api
local M = {}
-- Creates a cache table for buffers keyed by a type name.
-- Cache entries attach to the buffer and cleanup entries
-- as buffers are detached.
function M.create_buffer_cache()
local cache = {}
---@type table<integer, table<string, any>>
local items = setmetatable({}, {
__index = function(tbl, key)
rawset(tbl, key, {})
return rawget(tbl, key)
end,
})
---@type table<integer, boolean>
local loaded_buffers = {}
---@param type_name string
---@param bufnr integer
---@param value any
function cache.set(type_name, bufnr, value)
if not loaded_buffers[bufnr] then
loaded_buffers[bufnr] = true
-- Clean up the cache if the buffer is detached
-- to avoid memory leaks
api.nvim_buf_attach(bufnr, false, {
on_detach = function()
cache.clear_buffer(bufnr)
loaded_buffers[bufnr] = nil
return true
end,
on_reload = function() end, -- this is needed to prevent on_detach being called on buffer reload
})
end
items[bufnr][type_name] = value
end
---@param type_name string
---@param bufnr integer
---@return any
function cache.get(type_name, bufnr)
return items[bufnr][type_name]
end
---@param type_name string
---@param bufnr integer
---@return boolean
function cache.has(type_name, bufnr)
return cache.get(type_name, bufnr) ~= nil
end
---@param type_name string
---@param bufnr integer
function cache.remove(type_name, bufnr)
items[bufnr][type_name] = nil
end
---@param bufnr integer
function cache.clear_buffer(bufnr)
items[bufnr] = nil
end
return cache
end
return M

View file

@ -1,39 +0,0 @@
-- Shim module to address deprecations across nvim versions
local ts = vim.treesitter
local tsq = ts.query
local M = {}
function M.get_query_files(lang, query_group, is_included)
return (tsq.get_files or tsq.get_query_files)(lang, query_group, is_included)
end
function M.get_query(lang, query_name)
return (tsq.get or tsq.get_query)(lang, query_name)
end
function M.parse_query(lang, query)
return (tsq.parse or tsq.parse_query)(lang, query)
end
function M.get_range(node, source, metadata)
return (ts.get_range or tsq.get_range)(node, source, metadata)
end
function M.get_node_text(node, bufnr)
return (ts.get_node_text or tsq.get_node_text)(node, bufnr)
end
function M.require_language(lang, opts)
return (ts.language.add or ts.language.require_language)(lang, opts)
end
function M.flatten(t)
if vim.fn.has "nvim-0.11" == 1 then
return vim.iter(t):flatten():totable()
else
return vim.tbl_flatten(t)
end
end
return M

View file

@ -0,0 +1,174 @@
local M = {}
M.tiers = { 'stable', 'unstable', 'unmaintained', 'unsupported' }
---@class TSConfig
---@field install_dir string
---@type TSConfig
local config = {
install_dir = vim.fs.joinpath(vim.fn.stdpath('data') --[[@as string]], 'site'),
}
---Setup call for users to override configuration configurations.
---@param user_data TSConfig? user configuration table
function M.setup(user_data)
if user_data then
if user_data.install_dir then
user_data.install_dir = vim.fs.normalize(user_data.install_dir)
vim.o.rtp = user_data.install_dir .. ',' .. vim.o.rtp
end
config = vim.tbl_deep_extend('force', config, user_data)
end
end
-- Returns the install path for parsers, parser info, and queries.
-- If the specified directory does not exist, it is created.
---@param dir_name string
---@return string
function M.get_install_dir(dir_name)
local dir = vim.fs.joinpath(config.install_dir, dir_name)
if not vim.uv.fs_stat(dir) then
local ok, err = pcall(vim.fn.mkdir, dir, 'p', '0755')
if not ok then
local log = require('nvim-treesitter.log')
log.error(err --[[@as string]])
end
end
return dir
end
---@param type 'queries'|'parsers'?
---@return string[]
function M.get_installed(type)
local installed = {} --- @type table<string, boolean>
if not (type and type == 'parsers') then
for f in vim.fs.dir(M.get_install_dir('queries')) do
installed[f] = true
end
end
if not (type and type == 'queries') then
for f in vim.fs.dir(M.get_install_dir('parser')) do
installed[vim.fn.fnamemodify(f, ':r')] = true
end
end
return vim.tbl_keys(installed)
end
-- Get a list of all available parsers
---@param tier integer? only get parsers of specified tier
---@return string[]
function M.get_available(tier)
vim.api.nvim_exec_autocmds('User', { pattern = 'TSUpdate' })
local parsers = require('nvim-treesitter.parsers')
--- @type string[]
local languages = vim.tbl_keys(parsers)
table.sort(languages)
if tier then
languages = vim.tbl_filter(
--- @param p string
function(p)
return parsers[p] ~= nil and parsers[p].tier == tier
end,
languages
)
end
return languages
end
local function expand_tiers(list)
for i, tier in ipairs(M.tiers) do
if vim.list_contains(list, tier) then
list = vim.tbl_filter(
--- @param l string
function(l)
return l ~= tier
end,
list
)
vim.list_extend(list, M.get_available(i))
end
end
return list
end
---Normalize languages
---@param languages? string[]|string
---@param skip? { missing: boolean?, unsupported: boolean?, installed: boolean?, dependencies: boolean? }
---@return string[]
function M.norm_languages(languages, skip)
if not languages then
return {}
elseif type(languages) == 'string' then
languages = { languages }
end
if vim.list_contains(languages, 'all') then
if skip and skip.missing then
return M.get_installed()
end
languages = M.get_available()
end
languages = expand_tiers(languages)
if skip and skip.installed then
local installed = M.get_installed()
languages = vim.tbl_filter(
--- @param v string
function(v)
return not vim.list_contains(installed, v)
end,
languages
)
end
if skip and skip.missing then
local installed = M.get_installed()
languages = vim.tbl_filter(
--- @param v string
function(v)
return vim.list_contains(installed, v)
end,
languages
)
end
local parsers = require('nvim-treesitter.parsers')
languages = vim.tbl_filter(
--- @param v string
function(v)
if parsers[v] ~= nil then
return true
else
require('nvim-treesitter.log').warn('skipping unsupported language: ' .. v)
return false
end
end,
languages
)
if skip and skip.unsupported then
languages = vim.tbl_filter(
--- @param v string
function(v)
return not (parsers[v] and parsers[v].tier and parsers[v].tier == 4)
end,
languages
)
end
if not (skip and skip.dependencies) then
for _, lang in pairs(languages) do
if parsers[lang] and parsers[lang].requires then
vim.list_extend(languages, parsers[lang].requires)
end
end
end
return vim.list.unique(languages)
end
return M

View file

@ -1,616 +0,0 @@
local api = vim.api
local queries = require "nvim-treesitter.query"
local ts = require "nvim-treesitter.compat"
local parsers = require "nvim-treesitter.parsers"
local utils = require "nvim-treesitter.utils"
local caching = require "nvim-treesitter.caching"
local M = {}
---@class TSConfig
---@field modules {[string]:TSModule}
---@field sync_install boolean
---@field ensure_installed string[]|string
---@field ignore_install string[]
---@field auto_install boolean
---@field parser_install_dir string|nil
---@type TSConfig
local config = {
modules = {},
sync_install = false,
ensure_installed = {},
auto_install = false,
ignore_install = {},
parser_install_dir = nil,
}
-- List of modules that need to be setup on initialization.
---@type TSModule[][]
local queued_modules_defs = {}
-- Whether we've initialized the plugin yet.
local is_initialized = false
---@class TSModule
---@field module_path string
---@field enable boolean|string[]|function(string): boolean
---@field disable boolean|string[]|function(string): boolean
---@field keymaps table<string, string>
---@field is_supported function(string): boolean
---@field attach function(string)
---@field detach function(string)
---@field enabled_buffers table<integer, boolean>
---@field additional_vim_regex_highlighting boolean|string[]
---@type {[string]: TSModule}
local builtin_modules = {
highlight = {
module_path = "nvim-treesitter.highlight",
-- @deprecated: use `highlight.set_custom_captures` instead
custom_captures = {},
enable = false,
is_supported = function(lang)
return queries.has_highlights(lang)
end,
additional_vim_regex_highlighting = false,
},
incremental_selection = {
module_path = "nvim-treesitter.incremental_selection",
enable = false,
keymaps = {
init_selection = "gnn", -- set to `false` to disable one of the mappings
node_incremental = "grn",
scope_incremental = "grc",
node_decremental = "grm",
},
is_supported = function()
return true
end,
},
indent = {
module_path = "nvim-treesitter.indent",
enable = false,
is_supported = queries.has_indents,
},
}
local attached_buffers_by_module = caching.create_buffer_cache()
---Resolves a module by requiring the `module_path` or using the module definition.
---@param mod_name string
---@return TSModule|nil
local function resolve_module(mod_name)
local config_mod = M.get_module(mod_name)
if not config_mod then
return
end
if type(config_mod.attach) == "function" and type(config_mod.detach) == "function" then
return config_mod
elseif type(config_mod.module_path) == "string" then
return require(config_mod.module_path)
end
end
---Enables and attaches the module to a buffer for lang.
---@param mod string path to module
---@param bufnr integer|nil buffer number, defaults to current buffer
---@param lang string|nil language, defaults to current language
local function enable_module(mod, bufnr, lang)
local module = M.get_module(mod)
if not module then
return
end
bufnr = bufnr or api.nvim_get_current_buf()
lang = lang or parsers.get_buf_lang(bufnr)
if not module.enable then
if module.enabled_buffers then
module.enabled_buffers[bufnr] = true
else
module.enabled_buffers = { [bufnr] = true }
end
end
M.attach_module(mod, bufnr, lang)
end
---Enables autocomands for the module.
---After the module is loaded `loaded` will be set to true for the module.
---@param mod string path to module
local function enable_mod_conf_autocmd(mod)
local config_mod = M.get_module(mod)
if not config_mod or config_mod.loaded then
return
end
api.nvim_create_autocmd("FileType", {
group = api.nvim_create_augroup("NvimTreesitter-" .. mod, {}),
callback = function(args)
require("nvim-treesitter.configs").reattach_module(mod, args.buf)
end,
desc = "Reattach module",
})
config_mod.loaded = true
end
---Enables the module globally and for all current buffers.
---After enabled, `enable` will be set to true for the module.
---@param mod string path to module
local function enable_all(mod)
local config_mod = M.get_module(mod)
if not config_mod then
return
end
enable_mod_conf_autocmd(mod)
config_mod.enable = true
config_mod.enabled_buffers = nil
for _, bufnr in pairs(api.nvim_list_bufs()) do
enable_module(mod, bufnr)
end
end
---Disables and detaches the module for a buffer.
---@param mod string path to module
---@param bufnr integer buffer number, defaults to current buffer
local function disable_module(mod, bufnr)
local module = M.get_module(mod)
if not module then
return
end
bufnr = bufnr or api.nvim_get_current_buf()
if module.enabled_buffers then
module.enabled_buffers[bufnr] = false
end
M.detach_module(mod, bufnr)
end
---Disables autocomands for the module.
---After the module is unloaded `loaded` will be set to false for the module.
---@param mod string path to module
local function disable_mod_conf_autocmd(mod)
local config_mod = M.get_module(mod)
if not config_mod or not config_mod.loaded then
return
end
api.nvim_clear_autocmds { event = "FileType", group = "NvimTreesitter-" .. mod }
config_mod.loaded = false
end
---Disables the module globally and for all current buffers.
---After disabled, `enable` will be set to false for the module.
---@param mod string path to module
local function disable_all(mod)
local config_mod = M.get_module(mod)
if not config_mod then
return
end
config_mod.enabled_buffers = nil
disable_mod_conf_autocmd(mod)
config_mod.enable = false
for _, bufnr in pairs(api.nvim_list_bufs()) do
disable_module(mod, bufnr)
end
end
---Toggles a module for a buffer
---@param mod string path to module
---@param bufnr integer buffer number, defaults to current buffer
---@param lang string language, defaults to current language
local function toggle_module(mod, bufnr, lang)
bufnr = bufnr or api.nvim_get_current_buf()
lang = lang or parsers.get_buf_lang(bufnr)
if attached_buffers_by_module.has(mod, bufnr) then
disable_module(mod, bufnr)
else
enable_module(mod, bufnr, lang)
end
end
-- Toggles the module globally and for all current buffers.
-- @param mod path to module
local function toggle_all(mod)
local config_mod = M.get_module(mod)
if not config_mod then
return
end
if config_mod.enable then
disable_all(mod)
else
enable_all(mod)
end
end
---Recurses through all modules including submodules
---@param accumulator function called for each module
---@param root {[string]: TSModule}|nil root configuration table to start at
---@param path string|nil prefix path
local function recurse_modules(accumulator, root, path)
root = root or config.modules
for name, module in pairs(root) do
local new_path = path and (path .. "." .. name) or name
if M.is_module(module) then
accumulator(name, module, new_path, root)
elseif type(module) == "table" then
recurse_modules(accumulator, module, new_path)
end
end
end
-- Shows current configuration of all nvim-treesitter modules
---@param process_function function used as the `process` parameter
--- for vim.inspect (https://github.com/kikito/inspect.lua#optionsprocess)
local function config_info(process_function)
process_function = process_function
or function(item, path)
if path[#path] == vim.inspect.METATABLE then
return
end
if path[#path] == "is_supported" then
return
end
return item
end
print(vim.inspect(config, { process = process_function }))
end
---@param query_group string
---@param lang string
function M.edit_query_file(query_group, lang)
lang = lang or parsers.get_buf_lang()
local files = ts.get_query_files(lang, query_group, true)
if #files == 0 then
utils.notify "No query file found! Creating a new one!"
M.edit_query_file_user_after(query_group, lang)
elseif #files == 1 then
vim.cmd(":edit " .. files[1])
else
vim.ui.select(files, { prompt = "Select a file:" }, function(file)
if file then
vim.cmd(":edit " .. file)
end
end)
end
end
---@param query_group string
---@param lang string
function M.edit_query_file_user_after(query_group, lang)
lang = lang or parsers.get_buf_lang()
local folder = utils.join_path(vim.fn.stdpath "config", "after", "queries", lang)
local file = utils.join_path(folder, query_group .. ".scm")
if vim.fn.isdirectory(folder) ~= 1 then
vim.ui.select({ "Yes", "No" }, { prompt = '"' .. folder .. '" does not exist. Create it?' }, function(choice)
if choice == "Yes" then
vim.fn.mkdir(folder, "p", "0755")
vim.cmd(":edit " .. file)
end
end)
else
vim.cmd(":edit " .. file)
end
end
M.commands = {
TSBufEnable = {
run = enable_module,
args = {
"-nargs=1",
"-complete=custom,nvim_treesitter#available_modules",
},
},
TSBufDisable = {
run = disable_module,
args = {
"-nargs=1",
"-complete=custom,nvim_treesitter#available_modules",
},
},
TSBufToggle = {
run = toggle_module,
args = {
"-nargs=1",
"-complete=custom,nvim_treesitter#available_modules",
},
},
TSEnable = {
run = enable_all,
args = {
"-nargs=+",
"-complete=custom,nvim_treesitter#available_modules",
},
},
TSDisable = {
run = disable_all,
args = {
"-nargs=+",
"-complete=custom,nvim_treesitter#available_modules",
},
},
TSToggle = {
run = toggle_all,
args = {
"-nargs=+",
"-complete=custom,nvim_treesitter#available_modules",
},
},
TSConfigInfo = {
run = config_info,
args = {
"-nargs=0",
},
},
TSEditQuery = {
run = M.edit_query_file,
args = {
"-nargs=+",
"-complete=custom,nvim_treesitter#available_query_groups",
},
},
TSEditQueryUserAfter = {
run = M.edit_query_file_user_after,
args = {
"-nargs=+",
"-complete=custom,nvim_treesitter#available_query_groups",
},
},
}
---@param mod string module
---@param lang string the language of the buffer
---@param bufnr integer the buffer
function M.is_enabled(mod, lang, bufnr)
if not parsers.has_parser(lang) then
return false
end
local module_config = M.get_module(mod)
if not module_config then
return false
end
local buffer_enabled = module_config.enabled_buffers and module_config.enabled_buffers[bufnr]
local config_enabled = module_config.enable or buffer_enabled
if not config_enabled or not module_config.is_supported(lang) then
return false
end
local disable = module_config.disable
if type(disable) == "function" then
if disable(lang, bufnr) then
return false
end
elseif type(disable) == "table" then
-- Otherwise it's a list of languages
for _, parser in pairs(disable) do
if lang == parser then
return false
end
end
end
return true
end
---Setup call for users to override module configurations.
---@param user_data TSConfig module overrides
function M.setup(user_data)
config.modules = vim.tbl_deep_extend("force", config.modules, user_data)
config.ignore_install = user_data.ignore_install or {}
config.parser_install_dir = user_data.parser_install_dir or nil
if config.parser_install_dir then
config.parser_install_dir = vim.fn.expand(config.parser_install_dir, ":p")
end
config.auto_install = user_data.auto_install or false
if config.auto_install then
require("nvim-treesitter.install").setup_auto_install()
end
local ensure_installed = user_data.ensure_installed or {}
if #ensure_installed > 0 then
if user_data.sync_install then
require("nvim-treesitter.install").ensure_installed_sync(ensure_installed)
else
require("nvim-treesitter.install").ensure_installed(ensure_installed)
end
end
config.modules.ensure_installed = nil
config.ensure_installed = ensure_installed
recurse_modules(function(_, _, new_path)
local data = utils.get_at_path(config.modules, new_path)
if data.enable then
enable_all(new_path)
end
end, config.modules)
end
-- Defines a table of modules that can be attached/detached to buffers
-- based on language support. A module consist of the following properties:
---* @enable Whether the modules is enabled. Can be true or false.
---* @disable A list of languages to disable the module for. Only relevant if enable is true.
---* @keymaps A list of user mappings for a given module if relevant.
---* @is_supported A function which, given a ft, will return true if the ft works on the module.
---* @module_path A string path to a module file using `require`. The exported module must contain
--- an `attach` and `detach` function. This path is not required if `attach` and `detach`
--- functions are provided directly on the module definition.
---* @attach An attach function that is called for each buffer that the module is enabled for. This is required
--- if a `module_path` is not specified.
---* @detach A detach function that is called for each buffer that the module is enabled for. This is required
--- if a `module_path` is not specified.
--
-- Modules are not setup until `init` is invoked by the plugin. This allows modules to be defined in any order
-- and can be loaded lazily.
--
---* @example
---require"nvim-treesitter".define_modules {
--- my_cool_module = {
--- attach = function()
--- do_some_cool_setup()
--- end,
--- detach = function()
--- do_some_cool_teardown()
--- end
--- }
---}
---@param mod_defs TSModule[]
function M.define_modules(mod_defs)
if not is_initialized then
table.insert(queued_modules_defs, mod_defs)
return
end
recurse_modules(function(key, mod, _, group)
group[key] = vim.tbl_extend("keep", mod, {
enable = false,
disable = {},
is_supported = function()
return true
end,
})
end, mod_defs)
config.modules = vim.tbl_deep_extend("keep", config.modules, mod_defs)
for _, mod in ipairs(M.available_modules(mod_defs)) do
local module_config = M.get_module(mod)
if module_config and module_config.enable then
enable_mod_conf_autocmd(mod)
end
end
end
---Attaches a module to a buffer
---@param mod_name string the module name
---@param bufnr integer the buffer
---@param lang string the language of the buffer
function M.attach_module(mod_name, bufnr, lang)
bufnr = bufnr or api.nvim_get_current_buf()
lang = lang or parsers.get_buf_lang(bufnr)
local resolved_mod = resolve_module(mod_name)
if resolved_mod and not attached_buffers_by_module.has(mod_name, bufnr) and M.is_enabled(mod_name, lang, bufnr) then
attached_buffers_by_module.set(mod_name, bufnr, true)
resolved_mod.attach(bufnr, lang)
end
end
-- Detaches a module to a buffer
---@param mod_name string the module name
---@param bufnr integer the buffer
function M.detach_module(mod_name, bufnr)
local resolved_mod = resolve_module(mod_name)
bufnr = bufnr or api.nvim_get_current_buf()
if resolved_mod and attached_buffers_by_module.has(mod_name, bufnr) then
attached_buffers_by_module.remove(mod_name, bufnr)
resolved_mod.detach(bufnr)
end
end
-- Same as attach_module, but if the module is already attached, detach it first.
---@param mod_name string the module name
---@param bufnr integer the buffer
---@param lang string the language of the buffer
function M.reattach_module(mod_name, bufnr, lang)
M.detach_module(mod_name, bufnr)
M.attach_module(mod_name, bufnr, lang)
end
-- Gets available modules
---@param root {[string]:TSModule}|nil table to find modules
---@return string[] modules list of module paths
function M.available_modules(root)
local modules = {}
recurse_modules(function(_, _, path)
table.insert(modules, path)
end, root)
return modules
end
---Gets a module config by path
---@param mod_path string path to the module
---@return TSModule|nil: the module or nil
function M.get_module(mod_path)
local mod = utils.get_at_path(config.modules, mod_path)
return M.is_module(mod) and mod or nil
end
-- Determines whether the provided table is a module.
-- A module should contain an attach and detach function.
---@param mod table|nil the module table
---@return boolean
function M.is_module(mod)
return type(mod) == "table"
and ((type(mod.attach) == "function" and type(mod.detach) == "function") or type(mod.module_path) == "string")
end
-- Initializes built-in modules and any queued modules
-- registered by plugins or the user.
function M.init()
is_initialized = true
M.define_modules(builtin_modules)
for _, mod_def in ipairs(queued_modules_defs) do
M.define_modules(mod_def)
end
end
-- If parser_install_dir is not nil is used or created.
-- If parser_install_dir is nil try the package dir of the nvim-treesitter
-- plugin first, followed by the "site" dir from "runtimepath". "site" dir will
-- be created if it doesn't exist. Using only the package dir won't work when
-- the plugin is installed with Nix, since the "/nix/store" is read-only.
---@param folder_name string|nil
---@return string|nil, string|nil
function M.get_parser_install_dir(folder_name)
folder_name = folder_name or "parser"
local install_dir = config.parser_install_dir or utils.get_package_path()
local parser_dir = utils.join_path(install_dir, folder_name)
return utils.create_or_reuse_writable_dir(
parser_dir,
utils.join_space("Could not create parser dir '", parser_dir, "': "),
utils.join_space(
"Parser dir '",
parser_dir,
"' should be read/write (see README on how to configure an alternative install location)"
)
)
end
function M.get_parser_info_dir()
return M.get_parser_install_dir "parser-info"
end
function M.get_ignored_parser_installs()
return config.ignore_install or {}
end
function M.get_ensure_installed_parsers()
if type(config.ensure_installed) == "string" then
return { config.ensure_installed }
end
return config.ensure_installed or {}
end
return M

View file

@ -1,123 +0,0 @@
local api = vim.api
local tsutils = require "nvim-treesitter.ts_utils"
local query = require "nvim-treesitter.query"
local parsers = require "nvim-treesitter.parsers"
local M = {}
-- This is cached on buf tick to avoid computing that multiple times
-- Especially not for every line in the file when `zx` is hit
local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
local max_fold_level = api.nvim_win_get_option(0, "foldnestmax")
local trim_level = function(level)
if level > max_fold_level then
return max_fold_level
end
return level
end
local parser = parsers.get_parser(bufnr)
if not parser then
return {}
end
local matches = query.get_capture_matches_recursively(bufnr, function(lang)
if query.has_folds(lang) then
return "@fold", "folds"
elseif query.has_locals(lang) then
return "@scope", "locals"
end
end)
-- start..stop is an inclusive range
---@type table<number, number>
local start_counts = {}
---@type table<number, number>
local stop_counts = {}
local prev_start = -1
local prev_stop = -1
local min_fold_lines = api.nvim_win_get_option(0, "foldminlines")
for _, match in ipairs(matches) do
local start, stop, stop_col ---@type integer, integer, integer
if match.metadata and match.metadata.range then
start, _, stop, stop_col = unpack(match.metadata.range) ---@type integer, integer, integer, integer
else
start, _, stop, stop_col = match.node:range() ---@type integer, integer, integer, integer
end
if stop_col == 0 then
stop = stop - 1
end
local fold_length = stop - start + 1
local should_fold = fold_length > min_fold_lines
-- Fold only multiline nodes that are not exactly the same as previously met folds
-- Checking against just the previously found fold is sufficient if nodes
-- are returned in preorder or postorder when traversing tree
if should_fold and not (start == prev_start and stop == prev_stop) then
start_counts[start] = (start_counts[start] or 0) + 1
stop_counts[stop] = (stop_counts[stop] or 0) + 1
prev_start = start
prev_stop = stop
end
end
---@type string[]
local levels = {}
local current_level = 0
-- We now have the list of fold opening and closing, fill the gaps and mark where fold start
for lnum = 0, api.nvim_buf_line_count(bufnr) do
local prefix = ""
local last_trimmed_level = trim_level(current_level)
current_level = current_level + (start_counts[lnum] or 0)
local trimmed_level = trim_level(current_level)
current_level = current_level - (stop_counts[lnum] or 0)
local next_trimmed_level = trim_level(current_level)
-- Determine if it's the start/end of a fold
-- NB: vim's fold-expr interface does not have a mechanism to indicate that
-- two (or more) folds start at this line, so it cannot distinguish between
-- ( \n ( \n )) \n (( \n ) \n )
-- versus
-- ( \n ( \n ) \n ( \n ) \n )
-- If it did have such a mechanism, (trimmed_level - last_trimmed_level)
-- would be the correct number of starts to pass on.
if trimmed_level - last_trimmed_level > 0 then
prefix = ">"
elseif trimmed_level - next_trimmed_level > 0 then
-- Ending marks tend to confuse vim more than it helps, particularly when
-- the fold level changes by at least 2; we can uncomment this if
-- vim's behavior gets fixed.
-- prefix = "<"
prefix = ""
end
levels[lnum + 1] = prefix .. tostring(trimmed_level)
end
return levels
end)
---@param lnum integer
---@return string
function M.get_fold_indic(lnum)
if not parsers.has_parser() or not lnum then
return "0"
end
local buf = api.nvim_get_current_buf()
local levels = folds_levels(buf) or {}
return levels[lnum] or "0"
end
return M

View file

@ -1,176 +1,174 @@
local api = vim.api
local fn = vim.fn
local queries = require "nvim-treesitter.query"
local info = require "nvim-treesitter.info"
local shell = require "nvim-treesitter.shell_command_selectors"
local install = require "nvim-treesitter.install"
local utils = require "nvim-treesitter.utils"
local ts = require "nvim-treesitter.compat"
local health = vim.health or require "health"
-- "report_" prefix has been deprecated, use the recommended replacements if they exist.
local _start = health.start or health.report_start
local _ok = health.ok or health.report_ok
local _warn = health.warn or health.report_warn
local _error = health.error or health.report_error
local parsers = require('nvim-treesitter.parsers')
local config = require('nvim-treesitter.config')
local util = require('nvim-treesitter.util')
local tsq = vim.treesitter.query
local health = vim.health
local M = {}
local NVIM_TREESITTER_MINIMUM_ABI = 13
local TREE_SITTER_MIN_VER = { 0, 26, 1 }
---@param name string
---@return table?
local function check_exe(name)
if vim.fn.executable(name) == 1 then
local path = vim.fn.exepath(name)
local out = vim.trim(vim.fn.system({ name, '--version' }))
local version = vim.version.parse(out)
return { path = path, version = version, out = out }
end
end
local function install_health()
_start "Installation"
health.start('Requirements')
if fn.has "nvim-0.10" ~= 1 then
_error "Nvim-treesitter requires Nvim 0.10 or newer"
end
do -- nvim check
if vim.fn.has('nvim-0.12') ~= 1 then
health.error('Nvim-treesitter requires Neovim 0.12.0 or later.')
end
if fn.executable "tree-sitter" == 0 then
_warn(
"`tree-sitter` executable not found (parser generator, only needed for :TSInstallFromGrammar,"
.. " not required for :TSInstall)"
)
else
_ok(
"`tree-sitter` found "
.. (utils.ts_cli_version() or "(unknown version)")
.. " (parser generator, only needed for :TSInstallFromGrammar)"
)
end
if fn.executable "node" == 0 then
_warn("`node` executable not found (only needed for :TSInstallFromGrammar," .. " not required for :TSInstall)")
else
local handle = io.popen "node --version"
local result = handle:read "*a"
handle:close()
local version = vim.split(result, "\n")[1]
_ok("`node` found " .. version .. " (only needed for :TSInstallFromGrammar)")
end
if fn.executable "git" == 0 then
_error("`git` executable not found.", {
"Install it with your package manager.",
"Check that your `$PATH` is set correctly.",
})
else
_ok "`git` executable found."
end
local cc = shell.select_executable(install.compilers)
if not cc then
_error("`cc` executable not found.", {
"Check that any of "
.. vim.inspect(install.compilers)
.. " is in your $PATH"
.. ' or set the environment variable CC or `require"nvim-treesitter.install".compilers` explicitly!',
})
else
local version = vim.fn.systemlist(cc .. (cc == "cl" and "" or " --version"))[1]
_ok(
"`"
.. cc
.. "` executable found. Selected from "
.. vim.inspect(install.compilers)
.. (version and ("\nVersion: " .. version) or "")
)
end
if vim.treesitter.language_version then
if vim.treesitter.language_version >= NVIM_TREESITTER_MINIMUM_ABI then
_ok(
"Neovim was compiled with tree-sitter runtime ABI version "
health.ok(
'Neovim was compiled with tree-sitter runtime ABI version '
.. vim.treesitter.language_version
.. " (required >="
.. ' (required >='
.. NVIM_TREESITTER_MINIMUM_ABI
.. "). Parsers must be compatible with runtime ABI."
.. ').'
)
else
_error(
"Neovim was compiled with tree-sitter runtime ABI version "
health.error(
'Neovim was compiled with tree-sitter runtime ABI version '
.. vim.treesitter.language_version
.. ".\n"
.. "nvim-treesitter expects at least ABI version "
.. '.\n'
.. 'nvim-treesitter expects at least ABI version '
.. NVIM_TREESITTER_MINIMUM_ABI
.. "\n"
.. "Please make sure that Neovim is linked against are recent tree-sitter runtime when building"
.. " or raise an issue at your Neovim packager. Parsers must be compatible with runtime ABI."
.. '\n'
.. 'Please make sure that Neovim is linked against a recent tree-sitter library when building'
.. ' or raise an issue at your Neovim packager. Parsers must be compatible with runtime ABI.'
)
end
end
_start("OS Info:\n" .. vim.inspect(vim.loop.os_uname()))
do -- treesitter check
local ts = check_exe('tree-sitter')
if ts then
if vim.version.ge(ts.version, TREE_SITTER_MIN_VER) then
health.ok(string.format('tree-sitter-cli %s (%s)', ts.version, ts.path))
else
health.error(
string.format('tree-sitter-cli v%d.%d.%d is required', unpack(TREE_SITTER_MIN_VER))
)
end
else
health.error('tree-sitter-cli not found')
end
end
do -- curl+tar check
local tar = check_exe('tar')
if tar then
health.ok(string.format('tar %s (%s)', tar.version, tar.path))
else
health.error('tar not found')
end
local curl = check_exe('curl')
if curl then
health.ok(string.format('curl %s (%s)\n%s', curl.version, curl.path, curl.out))
else
health.error('curl not found')
end
end
health.start('OS Info')
local osinfo = vim.uv.os_uname() ---@type table<string,string>
for k, v in pairs(osinfo) do
health.info(k .. ': ' .. v)
end
local installdir = config.get_install_dir('')
health.start('Install directory for parsers and queries')
health.info(installdir)
if vim.uv.fs_access(installdir, 'w') then
health.ok('is writable.')
else
health.error('is not writable.')
end
if
vim.list_contains(vim.tbl_map(vim.fs.normalize, vim.api.nvim_list_runtime_paths()), installdir)
then
health.ok('is in runtimepath.')
else
health.error('is not in runtimepath.')
end
end
local function query_status(lang, query_group)
local ok, err = pcall(queries.get_query, lang, query_group)
local ok, err = pcall(tsq.get, lang, query_group)
if not ok then
return "x", err
return 'x', err
elseif not err then
return "."
return '.'
else
return ""
return ''
end
end
function M.check()
--- @type {[1]: string, [2]: string, [3]: string}[]
local error_collection = {}
-- Installation dependency checks
install_health()
queries.invalidate_query_cache()
-- Parser installation checks
local parser_installation = { "Parser/Features" .. string.rep(" ", 9) .. "H L F I J" }
for _, parser_name in pairs(info.installed_parsers()) do
local installed = #api.nvim_get_runtime_file("parser/" .. parser_name .. ".so", false)
-- Only append information about installed parsers
if installed >= 1 then
local multiple_parsers = installed > 1 and "+" or ""
local out = " - " .. parser_name .. multiple_parsers .. string.rep(" ", 20 - (#parser_name + #multiple_parsers))
for _, query_group in pairs(queries.built_in_query_groups) do
local status, err = query_status(parser_name, query_group)
out = out .. status .. " "
-- Parser installation checks
health.start('Installed languages' .. string.rep(' ', 5) .. 'H L F I J')
local languages = config.get_installed()
table.sort(languages)
for _, lang in ipairs(languages) do
local parser = parsers[lang]
local out = lang .. string.rep(' ', 22 - #lang)
if parser and parser.install_info then
for _, query_group in pairs(M.bundled_queries) do
local status, err = query_status(lang, query_group)
out = out .. status .. ' '
if err then
table.insert(error_collection, { parser_name, query_group, err })
table.insert(error_collection, { lang, query_group, err })
end
end
table.insert(parser_installation, vim.fn.trim(out, " ", 2))
end
if parser and parser.requires then
for _, p in pairs(parser.requires) do
if not vim.list_contains(languages, p) then
table.insert(error_collection, { lang, 'queries', 'dependency ' .. p .. ' missing' })
end
end
end
health.info(vim.fn.trim(out, ' ', 2))
end
local legend = [[
health.start(' Legend: [H]ighlights, [L]ocals, [F]olds, [I]ndents, In[J]ections')
Legend: H[ighlight], L[ocals], F[olds], I[ndents], In[j]ections
+) multiple parsers found, only one will be used
x) errors found in the query, try to run :TSUpdate {lang}]]
table.insert(parser_installation, legend)
-- Finally call the report function
_start(table.concat(parser_installation, "\n"))
if #error_collection > 0 then
_start "The following errors have been detected:"
health.start('The following errors have been detected in query files:')
for _, p in ipairs(error_collection) do
local lang, type, err = unpack(p)
local lang, type = p[1], p[2]
local lines = {}
table.insert(lines, lang .. "(" .. type .. "): " .. err)
local files = ts.get_query_files(lang, type)
table.insert(lines, lang .. '(' .. type .. '): ')
local files = tsq.get_files(lang, type)
if #files > 0 then
table.insert(lines, lang .. "(" .. type .. ") is concatenated from the following files:")
for _, file in ipairs(files) do
local fd = io.open(file, "r")
if fd then
local ok, file_err = pcall(ts.parse_query, lang, fd:read "*a")
if ok then
table.insert(lines, '| [OK]:"' .. file .. '"')
else
table.insert(lines, '| [ERROR]:"' .. file .. '", failed to load: ' .. file_err)
end
fd:close()
local query = util.read_file(file)
local _, file_err = pcall(tsq.parse, lang, query)
if file_err then
table.insert(lines, file)
end
end
end
_error(table.concat(lines, "\n"))
health.error(table.concat(lines, ''))
end
end
end
M.bundled_queries = { 'highlights', 'locals', 'folds', 'indents', 'injections' }
return M

View file

@ -1,49 +0,0 @@
local configs = require "nvim-treesitter.configs"
local M = {}
---@param config TSModule
---@param lang string
---@return boolean
local function should_enable_vim_regex(config, lang)
local additional_hl = config.additional_vim_regex_highlighting
local is_table = type(additional_hl) == "table"
---@diagnostic disable-next-line: param-type-mismatch
return additional_hl and (not is_table or vim.tbl_contains(additional_hl, lang))
end
---@param bufnr integer
---@param lang string
function M.attach(bufnr, lang)
local config = configs.get_module "highlight"
vim.treesitter.start(bufnr, lang)
if config and should_enable_vim_regex(config, lang) then
vim.bo[bufnr].syntax = "ON"
end
end
---@param bufnr integer
function M.detach(bufnr)
vim.treesitter.stop(bufnr)
end
---@deprecated
function M.start(...)
vim.notify(
"`nvim-treesitter.highlight.start` is deprecated: use `nvim-treesitter.highlight.attach` or `vim.treesitter.start`",
vim.log.levels.WARN
)
M.attach(...)
end
---@deprecated
function M.stop(...)
vim.notify(
"`nvim-treesitter.highlight.stop` is deprecated: use `nvim-treesitter.highlight.detach` or `vim.treesitter.stop`",
vim.log.levels.WARN
)
M.detach(...)
end
return M

View file

@ -1,176 +0,0 @@
local api = vim.api
local configs = require "nvim-treesitter.configs"
local ts_utils = require "nvim-treesitter.ts_utils"
local locals = require "nvim-treesitter.locals"
local parsers = require "nvim-treesitter.parsers"
local queries = require "nvim-treesitter.query"
local utils = require "nvim-treesitter.utils"
local M = {}
---@type table<integer, table<TSNode|nil>>
local selections = {}
function M.init_selection()
local buf = api.nvim_get_current_buf()
parsers.get_parser():parse { vim.fn.line "w0" - 1, vim.fn.line "w$" }
local node = ts_utils.get_node_at_cursor()
selections[buf] = { [1] = node }
ts_utils.update_selection(buf, node)
end
-- Get the range of the current visual selection.
--
-- The range starts with 1 and the ending is inclusive.
---@return integer, integer, integer, integer
local function visual_selection_range()
local _, csrow, cscol, _ = unpack(vim.fn.getpos "v") ---@type integer, integer, integer, integer
local _, cerow, cecol, _ = unpack(vim.fn.getpos ".") ---@type integer, integer, integer, integer
local start_row, start_col, end_row, end_col ---@type integer, integer, integer, integer
if csrow < cerow or (csrow == cerow and cscol <= cecol) then
start_row = csrow
start_col = cscol
end_row = cerow
end_col = cecol
else
start_row = cerow
start_col = cecol
end_row = csrow
end_col = cscol
end
return start_row, start_col, end_row, end_col
end
---@param node TSNode
---@return boolean
local function range_matches(node)
local csrow, cscol, cerow, cecol = visual_selection_range()
local srow, scol, erow, ecol = ts_utils.get_vim_range { node:range() }
return srow == csrow and scol == cscol and erow == cerow and ecol == cecol
end
---@param get_parent fun(node: TSNode): TSNode|nil
---@return fun():nil
local function select_incremental(get_parent)
return function()
local buf = api.nvim_get_current_buf()
local nodes = selections[buf]
local csrow, cscol, cerow, cecol = visual_selection_range()
-- Initialize incremental selection with current selection
if not nodes or #nodes == 0 or not range_matches(nodes[#nodes]) then
local parser = parsers.get_parser()
parser:parse { vim.fn.line "w0" - 1, vim.fn.line "w$" }
local node = parser:named_node_for_range(
{ csrow - 1, cscol - 1, cerow - 1, cecol },
{ ignore_injections = false }
)
ts_utils.update_selection(buf, node)
if nodes and #nodes > 0 then
table.insert(selections[buf], node)
else
selections[buf] = { [1] = node }
end
return
end
-- Find a node that changes the current selection.
local node = nodes[#nodes] ---@type TSNode
while true do
local parent = get_parent(node)
if not parent or parent == node then
-- Keep searching in the parent tree
local root_parser = parsers.get_parser()
root_parser:parse { vim.fn.line "w0" - 1, vim.fn.line "w$" }
local current_parser = root_parser:language_for_range { csrow - 1, cscol - 1, cerow - 1, cecol }
if root_parser == current_parser then
node = root_parser:named_node_for_range { csrow - 1, cscol - 1, cerow - 1, cecol }
ts_utils.update_selection(buf, node)
return
end
-- NOTE: parent() method is private
local parent_parser = current_parser:parent()
parent = parent_parser:named_node_for_range { csrow - 1, cscol - 1, cerow - 1, cecol }
end
node = parent
local srow, scol, erow, ecol = ts_utils.get_vim_range { node:range() }
local same_range = (srow == csrow and scol == cscol and erow == cerow and ecol == cecol)
if not same_range then
table.insert(selections[buf], node)
if node ~= nodes[#nodes] then
table.insert(nodes, node)
end
ts_utils.update_selection(buf, node)
return
end
end
end
end
M.node_incremental = select_incremental(function(node)
return node:parent() or node
end)
M.scope_incremental = select_incremental(function(node)
local lang = parsers.get_buf_lang()
if queries.has_locals(lang) then
return locals.containing_scope(node:parent() or node)
else
return node
end
end)
function M.node_decremental()
local buf = api.nvim_get_current_buf()
local nodes = selections[buf]
if not nodes or #nodes < 2 then
return
end
table.remove(selections[buf])
local node = nodes[#nodes] ---@type TSNode
ts_utils.update_selection(buf, node)
end
local FUNCTION_DESCRIPTIONS = {
init_selection = "Start selecting nodes with nvim-treesitter",
node_incremental = "Increment selection to named node",
scope_incremental = "Increment selection to surrounding scope",
node_decremental = "Shrink selection to previous named node",
}
---@param bufnr integer
function M.attach(bufnr)
local config = configs.get_module "incremental_selection"
for funcname, mapping in pairs(config.keymaps) do
if mapping then
local mode = funcname == "init_selection" and "n" or "x"
local rhs = M[funcname] ---@type function
if not rhs then
utils.notify("Unknown keybinding: " .. funcname .. debug.traceback(), vim.log.levels.ERROR)
else
vim.keymap.set(mode, mapping, rhs, { buffer = bufnr, silent = true, desc = FUNCTION_DESCRIPTIONS[funcname] })
end
end
end
end
function M.detach(bufnr)
local config = configs.get_module "incremental_selection"
for f, mapping in pairs(config.keymaps) do
if mapping then
local mode = f == "init_selection" and "n" or "x"
local ok, err = pcall(vim.keymap.del, mode, mapping, { buffer = bufnr })
if not ok then
utils.notify(string.format('%s "%s" for mode %s', err, mapping, mode), vim.log.levels.ERROR)
end
end
end
end
return M

View file

@ -1,33 +1,30 @@
local ts = vim.treesitter
local parsers = require "nvim-treesitter.parsers"
local M = {}
M.avoid_force_reparsing = {
yaml = true,
}
M.comment_parsers = {
comment = true,
luadoc = true,
javadoc = true,
jsdoc = true,
phpdoc = true,
}
local function getline(lnum)
return vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, false)[1] or ""
return vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, false)[1] or ''
end
---@param lnum integer
---@return integer
local function get_indentcols_at_line(lnum)
local _, indentcols = getline(lnum):find "^%s*"
local _, indentcols = getline(lnum):find('^%s*')
return indentcols or 0
end
---@param root TSNode
---@param lnum integer
---@param col? integer
---@return TSNode
---@return TSNode?
local function get_first_node_at_line(root, lnum, col)
col = col or get_indentcols_at_line(lnum)
return root:descendant_for_range(lnum - 1, col, lnum - 1, col + 1)
@ -36,25 +33,17 @@ end
---@param root TSNode
---@param lnum integer
---@param col? integer
---@return TSNode
---@return TSNode?
local function get_last_node_at_line(root, lnum, col)
col = col or (#getline(lnum) - 1)
return root:descendant_for_range(lnum - 1, col, lnum - 1, col + 1)
end
---@param node TSNode
---@return number
local function node_length(node)
local _, _, start_byte = node:start()
local _, _, end_byte = node:end_()
return end_byte - start_byte
end
---@param bufnr integer
---@param node TSNode
---@param delimiter string
---@return TSNode|nil child
---@return boolean|nil is_end
---@return TSNode? child
---@return boolean? is_end
local function find_delimiter(bufnr, node, delimiter)
for child, _ in node:iter_children() do
if child:type() == delimiter then
@ -62,8 +51,9 @@ local function find_delimiter(bufnr, node, delimiter)
local line = vim.api.nvim_buf_get_lines(bufnr, linenr, linenr + 1, false)[1]
local end_char = { child:end_() }
local trimmed_after_delim
local escaped_delimiter = delimiter:gsub("[%-%.%+%[%]%(%)%$%^%%%?%*]", "%%%1")
trimmed_after_delim, _ = line:sub(end_char[2] + 1):gsub("[%s" .. escaped_delimiter .. "]*", "")
local escaped_delimiter = delimiter:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]', '%%%1')
trimmed_after_delim =
assert(line):sub(end_char[2] + 1):gsub('[%s' .. escaped_delimiter .. ']*', '')
return child, #trimmed_after_delim == 0
end
end
@ -75,7 +65,7 @@ end
---@param hash_fn fun(...): any
---@return F
local function memoize(fn, hash_fn)
local cache = setmetatable({}, { __mode = "kv" }) ---@type table<any,any>
local cache = setmetatable({}, { __mode = 'kv' }) ---@type table<any,any>
return function(...)
local key = hash_fn(...)
@ -90,59 +80,53 @@ local function memoize(fn, hash_fn)
end
local get_indents = memoize(function(bufnr, root, lang)
---@type table<string,table<string,table>>
local map = {
["indent.auto"] = {},
["indent.begin"] = {},
["indent.end"] = {},
["indent.dedent"] = {},
["indent.branch"] = {},
["indent.ignore"] = {},
["indent.align"] = {},
["indent.zero"] = {},
['indent.auto'] = {},
['indent.begin'] = {},
['indent.end'] = {},
['indent.dedent'] = {},
['indent.branch'] = {},
['indent.ignore'] = {},
['indent.align'] = {},
['indent.zero'] = {},
}
--TODO(clason): remove when dropping Nvim 0.8 compat
local query = (ts.query.get or ts.get_query)(lang, "indents")
local query = ts.query.get(lang, 'indents')
if not query then
return map
end
for id, node, metadata in query:iter_captures(root, bufnr) do
if query.captures[id]:sub(1, 1) ~= "_" then
if assert(query.captures[id]):sub(1, 1) ~= '_' then
map[query.captures[id]][node:id()] = metadata or {}
end
end
return map
end, function(bufnr, root, lang)
return tostring(bufnr) .. root:id() .. "_" .. lang
return tostring(bufnr) .. root:id() .. '_' .. lang
end)
---@param lnum number (1-indexed)
---@param lnum integer (1-indexed)
---@return integer
function M.get_indent(lnum)
local bufnr = vim.api.nvim_get_current_buf()
local parser = parsers.get_parser(bufnr)
local parser = ts.get_parser(bufnr)
if not parser or not lnum then
return -1
end
--TODO(clason): replace when dropping Nvim 0.8 compat
local root_lang = parsers.get_buf_lang(bufnr)
-- some languages like Python will actually have worse results when re-parsing at opened new line
if not M.avoid_force_reparsing[root_lang] then
-- Reparse in case we got triggered by ":h indentkeys"
parser:parse { vim.fn.line "w0" - 1, vim.fn.line "w$" }
end
parser:parse({ vim.fn.line('w0') - 1, vim.fn.line('w$') })
-- Get language tree with smallest range around node that's not a comment parser
local root, lang_tree ---@type TSNode, LanguageTree
local root, lang_tree ---@type TSNode, vim.treesitter.LanguageTree
parser:for_each_tree(function(tstree, tree)
if not tstree or M.comment_parsers[tree:lang()] then
return
end
local local_root = tstree:root()
if ts.is_in_node_range(local_root, lnum - 1, 0) then
if not root or node_length(root) >= node_length(local_root) then
if not root or root:byte_length() >= local_root:byte_length() then
root = local_root
lang_tree = tree
end
@ -155,20 +139,19 @@ function M.get_indent(lnum)
end
local q = get_indents(vim.api.nvim_get_current_buf(), root, lang_tree:lang())
local is_empty_line = string.match(getline(lnum), "^%s*$") ~= nil
local node ---@type TSNode
if is_empty_line then
local node ---@type TSNode?
if getline(lnum):find('^%s*$') then
local prevlnum = vim.fn.prevnonblank(lnum)
local indentcols = get_indentcols_at_line(prevlnum)
local prevline = vim.trim(getline(prevlnum))
-- The final position can be trailing spaces, which should not affect indentation
node = get_last_node_at_line(root, prevlnum, indentcols + #prevline - 1)
if node:type():match "comment" then
if node and node:type():match('comment') then
-- The final node we capture of the previous line can be a comment node, which should also be ignored
-- Unless the last line is an entire line of comment, ignore the comment range and find the last node again
local first_node = get_first_node_at_line(root, prevlnum, indentcols)
local _, scol, _, _ = node:range()
if first_node:id() ~= node:id() then
if first_node and first_node:id() ~= node:id() then
-- In case the last captured node is a trailing comment node, re-trim the string
prevline = vim.trim(prevline:sub(1, scol - indentcols))
-- Add back indent as indent of prevline was trimmed away
@ -176,7 +159,7 @@ function M.get_indent(lnum)
node = get_last_node_at_line(root, prevlnum, col)
end
end
if q["indent.end"][node:id()] then
if node and q['indent.end'][node:id()] then
node = get_first_node_at_line(root, lnum)
end
else
@ -192,18 +175,18 @@ function M.get_indent(lnum)
end
-- tracks to ensure multiple indent levels are not applied for same line
local is_processed_by_row = {}
local is_processed_by_row = {} --- @type table<integer,boolean>
if q["indent.zero"][node:id()] then
if node and q['indent.zero'][node:id()] then
return 0
end
while node do
-- do 'autoindent' if not marked as @indent
if
not q["indent.begin"][node:id()]
and not q["indent.align"][node:id()]
and q["indent.auto"][node:id()]
not q['indent.begin'][node:id()]
and not q['indent.align'][node:id()]
and q['indent.auto'][node:id()]
and node:start() < lnum - 1
and lnum - 1 <= node:end_()
then
@ -214,8 +197,8 @@ function M.get_indent(lnum)
-- If a node spans from L1,C1 to L2,C2, we know that lines where L1 < line <= L2 would
-- have their indentations contained by the node.
if
not q["indent.begin"][node:id()]
and q["indent.ignore"][node:id()]
not q['indent.begin'][node:id()]
and q['indent.ignore'][node:id()]
and node:start() < lnum - 1
and lnum - 1 <= node:end_()
then
@ -228,7 +211,10 @@ function M.get_indent(lnum)
if
not is_processed_by_row[srow]
and ((q["indent.branch"][node:id()] and srow == lnum - 1) or (q["indent.dedent"][node:id()] and srow ~= lnum - 1))
and (
(q['indent.branch'][node:id()] and srow == lnum - 1)
or (q['indent.dedent'][node:id()] and srow ~= lnum - 1)
)
then
indent = indent - indent_size
is_processed = true
@ -239,21 +225,21 @@ function M.get_indent(lnum)
local is_in_err = false
if should_process then
local parent = node:parent()
is_in_err = parent and parent:has_error()
is_in_err = parent and parent:has_error() or false
end
if
should_process
and (
q["indent.begin"][node:id()]
and (srow ~= erow or is_in_err or q["indent.begin"][node:id()]["indent.immediate"])
and (srow ~= lnum - 1 or q["indent.begin"][node:id()]["indent.start_at_same_line"])
q['indent.begin'][node:id()]
and (srow ~= erow or is_in_err or q['indent.begin'][node:id()]['indent.immediate'])
and (srow ~= lnum - 1 or q['indent.begin'][node:id()]['indent.start_at_same_line'])
)
then
indent = indent + indent_size
is_processed = true
end
if is_in_err and not q["indent.align"][node:id()] then
if is_in_err and not q['indent.align'][node:id()] then
-- only when the node is in error, promote the
-- first child's aligned indent to the error node
-- to work around ((ERROR "X" . (_)) @aligned_indent (#set! "delimiter" "AB"))
@ -261,34 +247,41 @@ function M.get_indent(lnum)
-- (ERROR "X" @aligned_indent (#set! "delimiter" "AB") . (_))
-- and we will fish it out here.
for c in node:iter_children() do
if q["indent.align"][c:id()] then
q["indent.align"][node:id()] = q["indent.align"][c:id()]
if q['indent.align'][c:id()] then
q['indent.align'][node:id()] = q['indent.align'][c:id()]
break
end
end
end
-- do not indent for nodes that starts-and-ends on same line and starts on target line (lnum)
if should_process and q["indent.align"][node:id()] and (srow ~= erow or is_in_err) and (srow ~= lnum - 1) then
local metadata = q["indent.align"][node:id()]
local o_delim_node, o_is_last_in_line ---@type TSNode|nil, boolean|nil
local c_delim_node, c_is_last_in_line ---@type TSNode|nil, boolean|nil, boolean|nil
if
should_process
and q['indent.align'][node:id()]
and (srow ~= erow or is_in_err)
and (srow ~= lnum - 1)
then
local metadata = q['indent.align'][node:id()]
local o_delim_node, o_is_last_in_line ---@type TSNode?, boolean?
local c_delim_node, c_is_last_in_line ---@type TSNode?, boolean?, boolean?
local indent_is_absolute = false
if metadata["indent.open_delimiter"] then
o_delim_node, o_is_last_in_line = find_delimiter(bufnr, node, metadata["indent.open_delimiter"])
if metadata['indent.open_delimiter'] then
o_delim_node, o_is_last_in_line =
find_delimiter(bufnr, node, metadata['indent.open_delimiter'])
else
o_delim_node = node
end
if metadata["indent.close_delimiter"] then
c_delim_node, c_is_last_in_line = find_delimiter(bufnr, node, metadata["indent.close_delimiter"])
if metadata['indent.close_delimiter'] then
c_delim_node, c_is_last_in_line =
find_delimiter(bufnr, node, metadata['indent.close_delimiter'])
else
c_delim_node = node
end
if o_delim_node then
local o_srow, o_scol = o_delim_node:start()
local c_srow = nil
local c_srow = nil --- @type integer?
if c_delim_node then
c_srow, _ = c_delim_node:start()
c_srow = c_delim_node:start()
end
if o_is_last_in_line then
-- hanging indent (previous line ended with starting delimiter)
@ -310,7 +303,7 @@ function M.get_indent(lnum)
-- Then its indent level shouldn't be affected by `@aligned_indent` node
indent = math.max(indent - indent_size, 0)
else
indent = o_scol + (metadata["indent.increment"] or 1)
indent = o_scol + (metadata['indent.increment'] or 1)
indent_is_absolute = true
end
end
@ -321,7 +314,7 @@ function M.get_indent(lnum)
-- then this last line may need additional indent to avoid clashes
-- with the next. `indent.avoid_last_matching_next` controls this behavior,
-- for example this is needed for function parameters.
avoid_last_matching_next = metadata["indent.avoid_last_matching_next"] or false
avoid_last_matching_next = metadata['indent.avoid_last_matching_next'] or false
end
if avoid_last_matching_next then
-- last line must be indented more in cases where
@ -350,17 +343,4 @@ function M.get_indent(lnum)
return indent
end
---@type table<integer, string>
local indent_funcs = {}
---@param bufnr integer
function M.attach(bufnr)
indent_funcs[bufnr] = vim.bo.indentexpr
vim.bo.indentexpr = "nvim_treesitter#indent()"
end
function M.detach(bufnr)
vim.bo.indentexpr = indent_funcs[bufnr]
end
return M

View file

@ -1,190 +0,0 @@
local api = vim.api
local configs = require "nvim-treesitter.configs"
local parsers = require "nvim-treesitter.parsers"
local M = {}
local function install_info()
local max_len = 0
for _, ft in pairs(parsers.available_parsers()) do
if #ft > max_len then
max_len = #ft
end
end
local parser_list = parsers.available_parsers()
table.sort(parser_list)
for _, lang in pairs(parser_list) do
local is_installed = #api.nvim_get_runtime_file("parser/" .. lang .. ".so", false) > 0
api.nvim_out_write(lang .. string.rep(" ", max_len - #lang + 1))
if is_installed then
api.nvim_out_write "[✓] installed\n"
elseif pcall(vim.treesitter.inspect_lang, lang) then
api.nvim_out_write "[✗] not installed (but still loaded. Restart Neovim!)\n"
else
api.nvim_out_write "[✗] not installed\n"
end
end
end
-- Sort a list of modules into namespaces.
-- {'mod1', 'mod2.sub1', 'mod2.sub2', 'mod3'}
-- ->
-- { default = {'mod1', 'mod3'}, mod2 = {'sub1', 'sub2'}}
---@param modulelist string[]
---@return table
local function namespace_modules(modulelist)
local modules = {}
for _, module in ipairs(modulelist) do
if module:find "%." then
local namespace, submodule = module:match "^(.*)%.(.*)$"
if not modules[namespace] then
modules[namespace] = {}
end
table.insert(modules[namespace], submodule)
else
if not modules.default then
modules.default = {}
end
table.insert(modules.default, module)
end
end
return modules
end
---@param list string[]
---@return integer length
local function longest_string_length(list)
local length = 0
for _, value in ipairs(list) do
if #value > length then
length = #value
end
end
return length
end
---@param curbuf integer
---@param origbuf integer
---@param parserlist string[]
---@param namespace string
---@param modulelist string[]
local function append_module_table(curbuf, origbuf, parserlist, namespace, modulelist)
local maxlen_parser = longest_string_length(parserlist)
table.sort(modulelist)
-- header
local header = ">> " .. namespace .. string.rep(" ", maxlen_parser - #namespace - 1)
for _, module in pairs(modulelist) do
header = header .. module .. " "
end
api.nvim_buf_set_lines(curbuf, -1, -1, true, { header })
-- actual table
for _, parser in ipairs(parserlist) do
local padding = string.rep(" ", maxlen_parser - #parser + 2)
local line = parser .. padding
local namespace_prefix = (namespace == "default") and "" or namespace .. "."
for _, module in pairs(modulelist) do
local modlen = #module
module = namespace_prefix .. module
if configs.is_enabled(module, parser, origbuf) then
line = line .. ""
else
line = line .. ""
end
line = line .. string.rep(" ", modlen + 1)
end
api.nvim_buf_set_lines(curbuf, -1, -1, true, { line })
end
api.nvim_buf_set_lines(curbuf, -1, -1, true, { "" })
end
local function print_info_modules(parserlist, module)
local origbuf = api.nvim_get_current_buf()
api.nvim_command "enew"
local curbuf = api.nvim_get_current_buf()
local modules
if module then
modules = namespace_modules { module }
else
modules = namespace_modules(configs.available_modules())
end
---@type string[]
local namespaces = {}
for k, _ in pairs(modules) do
table.insert(namespaces, k)
end
table.sort(namespaces)
table.sort(parserlist)
for _, namespace in ipairs(namespaces) do
append_module_table(curbuf, origbuf, parserlist, namespace, modules[namespace])
end
api.nvim_buf_set_option(curbuf, "modified", false)
api.nvim_buf_set_option(curbuf, "buftype", "nofile")
vim.cmd [[
syntax match TSModuleInfoGood //
syntax match TSModuleInfoBad //
syntax match TSModuleInfoHeader /^>>.*$/ contains=TSModuleInfoNamespace
syntax match TSModuleInfoNamespace /^>> \w*/ contained
syntax match TSModuleInfoParser /^[^> ]*\ze /
]]
local highlights = {
TSModuleInfoGood = { fg = "LightGreen", bold = true, default = true },
TSModuleInfoBad = { fg = "Crimson", default = true },
TSModuleInfoHeader = { link = "Type", default = true },
TSModuleInfoNamespace = { link = "Statement", default = true },
TSModuleInfoParser = { link = "Identifier", default = true },
}
for k, v in pairs(highlights) do
api.nvim_set_hl(0, k, v)
end
end
local function module_info(module)
if module and not configs.get_module(module) then
return
end
local parserlist = parsers.available_parsers()
if module then
print_info_modules(parserlist, module)
else
print_info_modules(parserlist)
end
end
---@return string[]
function M.installed_parsers()
local installed = {}
for _, p in pairs(parsers.available_parsers()) do
if parsers.has_parser(p) then
table.insert(installed, p)
end
end
return installed
end
M.commands = {
TSInstallInfo = {
run = install_info,
args = {
"-nargs=0",
},
},
TSModuleInfo = {
run = module_info,
args = {
"-nargs=?",
"-complete=custom,nvim_treesitter#available_modules",
},
},
}
return M

View file

@ -0,0 +1,31 @@
local M = {}
function M.setup(...)
require('nvim-treesitter.config').setup(...)
end
function M.get_available(...)
return require('nvim-treesitter.config').get_available(...)
end
function M.get_installed(...)
return require('nvim-treesitter.config').get_installed(...)
end
function M.install(...)
return require('nvim-treesitter.install').install(...)
end
function M.uninstall(...)
return require('nvim-treesitter.install').uninstall(...)
end
function M.update(...)
return require('nvim-treesitter.install').update(...)
end
function M.indentexpr()
return require('nvim-treesitter.indent').get_indent(vim.v.lnum)
end
return M

File diff suppressed because it is too large Load diff

View file

@ -1,365 +0,0 @@
-- Functions to handle locals
-- Locals are a generalization of definition and scopes
-- its the way nvim-treesitter uses to "understand" the code
local queries = require "nvim-treesitter.query"
local ts_utils = require "nvim-treesitter.ts_utils"
local ts = vim.treesitter
local api = vim.api
local M = {}
function M.collect_locals(bufnr)
return queries.collect_group_results(bufnr, "locals")
end
-- Iterates matches from a locals query file.
-- @param bufnr the buffer
-- @param root the root node
function M.iter_locals(bufnr, root)
return queries.iter_group_results(bufnr, "locals", root)
end
---@param bufnr integer
---@return any
function M.get_locals(bufnr)
return queries.get_matches(bufnr, "locals")
end
-- Creates unique id for a node based on text and range
---@param scope TSNode: the scope node of the definition
---@param node_text string: the node text to use
---@return string: a string id
function M.get_definition_id(scope, node_text)
-- Add a valid starting character in case node text doesn't start with a valid one.
return table.concat({ "k", node_text or "", scope:range() }, "_")
end
function M.get_definitions(bufnr)
local locals = M.get_locals(bufnr)
local defs = {}
for _, loc in ipairs(locals) do
if loc["local"]["definition"] then
table.insert(defs, loc["local"]["definition"])
end
end
return defs
end
function M.get_scopes(bufnr)
local locals = M.get_locals(bufnr)
local scopes = {}
for _, loc in ipairs(locals) do
if loc["local"]["scope"] and loc["local"]["scope"].node then
table.insert(scopes, loc["local"]["scope"].node)
end
end
return scopes
end
function M.get_references(bufnr)
local locals = M.get_locals(bufnr)
local refs = {}
for _, loc in ipairs(locals) do
if loc["local"]["reference"] and loc["local"]["reference"].node then
table.insert(refs, loc["local"]["reference"].node)
end
end
return refs
end
-- Gets a table with all the scopes containing a node
-- The order is from most specific to least (bottom up)
---@param node TSNode
---@param bufnr integer
---@return TSNode[]
function M.get_scope_tree(node, bufnr)
local scopes = {} ---@type TSNode[]
for scope in M.iter_scope_tree(node, bufnr) do
table.insert(scopes, scope)
end
return scopes
end
-- Iterates over a nodes scopes moving from the bottom up
---@param node TSNode
---@param bufnr integer
---@return fun(): TSNode|nil
function M.iter_scope_tree(node, bufnr)
local last_node = node
return function()
if not last_node then
return
end
local scope = M.containing_scope(last_node, bufnr, false) or ts_utils.get_root_for_node(node)
last_node = scope:parent()
return scope
end
end
-- Gets a table of all nodes and their 'kinds' from a locals list
---@param local_def any: the local list result
---@return table: a list of node entries
function M.get_local_nodes(local_def)
local result = {}
M.recurse_local_nodes(local_def, function(def, _node, kind)
table.insert(result, vim.tbl_extend("keep", { kind = kind }, def))
end)
return result
end
-- Recurse locals results until a node is found.
-- The accumulator function is given
-- * The table of the node
-- * The node
-- * The full definition match `@definition.var.something` -> 'var.something'
-- * The last definition match `@definition.var.something` -> 'something'
---@param local_def any The locals result
---@param accumulator function The accumulator function
---@param full_match? string The full match path to append to
---@param last_match? string The last match
function M.recurse_local_nodes(local_def, accumulator, full_match, last_match)
if type(local_def) ~= "table" then
return
end
if local_def.node then
accumulator(local_def, local_def.node, full_match, last_match)
else
for match_key, def in pairs(local_def) do
M.recurse_local_nodes(def, accumulator, full_match and (full_match .. "." .. match_key) or match_key, match_key)
end
end
end
-- Get a single dimension table to look definition nodes.
-- Keys are generated by using the range of the containing scope and the text of the definition node.
-- This makes looking up a definition for a given scope a simple key lookup.
--
-- This is memoized by buffer tick. If the function is called in succession
-- without the buffer tick changing, then the previous result will be used
-- since the syntax tree hasn't changed.
--
-- Usage lookups require finding the definition of the node, so `find_definition`
-- is called very frequently, which is why this lookup must be fast as possible.
--
---@param bufnr integer: the buffer
---@return table result: a table for looking up definitions
M.get_definitions_lookup_table = ts_utils.memoize_by_buf_tick(function(bufnr)
local definitions = M.get_definitions(bufnr)
local result = {}
for _, definition in ipairs(definitions) do
for _, node_entry in ipairs(M.get_local_nodes(definition)) do
local scopes = M.get_definition_scopes(node_entry.node, bufnr, node_entry.scope)
-- Always use the highest valid scope
local scope = scopes[#scopes]
local node_text = ts.get_node_text(node_entry.node, bufnr)
local id = M.get_definition_id(scope, node_text)
result[id] = node_entry
end
end
return result
end)
-- Gets all the scopes of a definition based on the scope type
-- Scope types can be
--
-- "parent": Uses the parent of the containing scope, basically, skipping a scope
-- "global": Uses the top most scope
-- "local": Uses the containing scope of the definition. This is the default
--
---@param node TSNode: the definition node
---@param bufnr integer: the buffer
---@param scope_type string: the scope type
function M.get_definition_scopes(node, bufnr, scope_type)
local scopes = {}
local scope_count = 1 ---@type integer|nil
-- Definition is valid for the containing scope
-- and the containing scope of that scope
if scope_type == "parent" then
scope_count = 2
-- Definition is valid in all parent scopes
elseif scope_type == "global" then
scope_count = nil
end
local i = 0
for scope in M.iter_scope_tree(node, bufnr) do
table.insert(scopes, scope)
i = i + 1
if scope_count and i >= scope_count then
break
end
end
return scopes
end
---@param node TSNode
---@param bufnr integer
---@return TSNode node
---@return TSNode scope
---@return string|nil kind
function M.find_definition(node, bufnr)
local def_lookup = M.get_definitions_lookup_table(bufnr)
local node_text = ts.get_node_text(node, bufnr)
for scope in M.iter_scope_tree(node, bufnr) do
local id = M.get_definition_id(scope, node_text)
if def_lookup[id] then
local entry = def_lookup[id]
return entry.node, scope, entry.kind
end
end
return node, ts_utils.get_root_for_node(node), nil
end
-- Finds usages of a node in a given scope.
---@param node TSNode the node to find usages for
---@param scope_node TSNode the node to look within
---@return TSNode[]: a list of nodes
function M.find_usages(node, scope_node, bufnr)
bufnr = bufnr or api.nvim_get_current_buf()
local node_text = ts.get_node_text(node, bufnr)
if not node_text or #node_text < 1 then
return {}
end
local scope_node = scope_node or ts_utils.get_root_for_node(node)
local usages = {}
for match in M.iter_locals(bufnr, scope_node) do
match = match["local"]
if match.reference and match.reference.node and ts.get_node_text(match.reference.node, bufnr) == node_text then
local def_node, _, kind = M.find_definition(match.reference.node, bufnr)
if kind == nil or def_node == node then
table.insert(usages, match.reference.node)
end
end
end
return usages
end
---@param node TSNode
---@param bufnr? integer
---@param allow_scope? boolean
---@return TSNode|nil
function M.containing_scope(node, bufnr, allow_scope)
local bufnr = bufnr or api.nvim_get_current_buf()
local allow_scope = allow_scope == nil or allow_scope == true
local scopes = M.get_scopes(bufnr)
if not node or not scopes then
return
end
local iter_node = node
while iter_node ~= nil and not vim.tbl_contains(scopes, iter_node) do
iter_node = iter_node:parent()
end
return iter_node or (allow_scope and node or nil)
end
function M.nested_scope(node, cursor_pos)
local bufnr = api.nvim_get_current_buf()
local scopes = M.get_scopes(bufnr)
if not node or not scopes then
return
end
local row = cursor_pos.row ---@type integer
local col = cursor_pos.col ---@type integer
local scope = M.containing_scope(node)
for _, child in ipairs(ts_utils.get_named_children(scope)) do
local row_, col_ = child:start()
if vim.tbl_contains(scopes, child) and ((row_ + 1 == row and col_ > col) or row_ + 1 > row) then
return child
end
end
end
function M.next_scope(node)
local bufnr = api.nvim_get_current_buf()
local scopes = M.get_scopes(bufnr)
if not node or not scopes then
return
end
local scope = M.containing_scope(node)
local parent = scope:parent()
if not parent then
return
end
local is_prev = true
for _, child in ipairs(ts_utils.get_named_children(parent)) do
if child == scope then
is_prev = false
elseif not is_prev and vim.tbl_contains(scopes, child) then
return child
end
end
end
---@param node TSNode
---@return TSNode|nil
function M.previous_scope(node)
local bufnr = api.nvim_get_current_buf()
local scopes = M.get_scopes(bufnr)
if not node or not scopes then
return
end
local scope = M.containing_scope(node)
local parent = scope:parent()
if not parent then
return
end
local is_prev = true
local children = ts_utils.get_named_children(parent)
for i = #children, 1, -1 do
if children[i] == scope then
is_prev = false
elseif not is_prev and vim.tbl_contains(scopes, children[i]) then
return children[i]
end
end
end
return M

100
lua/nvim-treesitter/log.lua Normal file
View file

@ -0,0 +1,100 @@
local echo = vim.api.nvim_echo
-- TODO(lewis6991): write these out to a file
local messages = {} --- @type {[1]: string, [2]: string?, [3]: string}[]
local sev_to_hl = {
trace = 'DiagnosticHint',
debug = 'Normal',
info = 'MoreMsg',
warn = 'WarningMsg',
error = 'ErrorMsg',
}
---@param ctx string?
---@return string
local function mkpfx(ctx)
return ctx and string.format('[nvim-treesitter/%s]', ctx) or '[nvim-treesitter]'
end
---@class TSLogModule
---@field trace fun(fmt: string, ...: any)
---@field debug fun(fmt: string, ...: any)
---@field info fun(fmt: string, ...: any)
---@field warn fun(fmt: string, ...: any)
---@field error fun(fmt: string, ...: any)
local M = {}
---@class Logger
---@field ctx? string
local Logger = {}
M.Logger = Logger
---@param ctx? string
---@return Logger
function M.new(ctx)
return setmetatable({ ctx = ctx }, { __index = Logger })
end
---@param m string
---@param ... any
function Logger:trace(m, ...)
messages[#messages + 1] = { 'trace', self.ctx, m:format(...) }
end
---@param m string
---@param ... any
function Logger:debug(m, ...)
messages[#messages + 1] = { 'debug', self.ctx, m:format(...) }
end
---@param m string
---@param ... any
function Logger:info(m, ...)
local m1 = m:format(...)
messages[#messages + 1] = { 'info', self.ctx, m1 }
echo({ { mkpfx(self.ctx) .. ': ' .. m1, sev_to_hl.info } }, true, {})
end
---@param m string
---@param ... any
function Logger:warn(m, ...)
local m1 = m:format(...)
messages[#messages + 1] = { 'warn', self.ctx, m1 }
echo({ { mkpfx(self.ctx) .. ' warning: ' .. m1, sev_to_hl.warn } }, true, {})
end
---@param m string
---@param ... any
---@return string
function Logger:error(m, ...)
local m1 = m:format(...)
messages[#messages + 1] = { 'error', self.ctx, m1 }
echo({ { mkpfx(self.ctx) .. ' error: ' .. m1, sev_to_hl.error } }, true, {})
return m1
end
local noctx_logger = M.new()
setmetatable(M, {
__index = function(t, k)
--- @diagnostic disable-next-line:no-unknown
t[k] = function(...)
return noctx_logger[k](noctx_logger, ...)
end
return t[k]
end,
})
function M.show()
for _, l in ipairs(messages) do
local sev, ctx, msg = l[1], l[2], l[3]
local hl = sev_to_hl[sev]
local text = ctx and string.format('%s(%s): %s', sev, ctx, msg)
or string.format('%s: %s', sev, msg)
echo({ { text, hl } }, false, {})
end
end
return M

File diff suppressed because it is too large Load diff

View file

@ -1,453 +0,0 @@
local api = vim.api
local ts = require "nvim-treesitter.compat"
local tsrange = require "nvim-treesitter.tsrange"
local utils = require "nvim-treesitter.utils"
local parsers = require "nvim-treesitter.parsers"
local caching = require "nvim-treesitter.caching"
local M = {}
local EMPTY_ITER = function() end
M.built_in_query_groups = { "highlights", "locals", "folds", "indents", "injections" }
-- Creates a function that checks whether a given query exists
-- for a specific language.
---@param query string
---@return fun(string): boolean
local function get_query_guard(query)
return function(lang)
return M.has_query_files(lang, query)
end
end
for _, query in ipairs(M.built_in_query_groups) do
M["has_" .. query] = get_query_guard(query)
end
---@return string[]
function M.available_query_groups()
local query_files = api.nvim_get_runtime_file("queries/*/*.scm", true)
local groups = {}
for _, f in ipairs(query_files) do
groups[vim.fn.fnamemodify(f, ":t:r")] = true
end
local list = {}
for k, _ in pairs(groups) do
table.insert(list, k)
end
return list
end
do
local query_cache = caching.create_buffer_cache()
local function update_cached_matches(bufnr, changed_tick, query_group)
query_cache.set(query_group, bufnr, {
tick = changed_tick,
cache = M.collect_group_results(bufnr, query_group) or {},
})
end
---@param bufnr integer
---@param query_group string
---@return any
function M.get_matches(bufnr, query_group)
bufnr = bufnr or api.nvim_get_current_buf()
local cached_local = query_cache.get(query_group, bufnr)
if not cached_local or api.nvim_buf_get_changedtick(bufnr) > cached_local.tick then
update_cached_matches(bufnr, api.nvim_buf_get_changedtick(bufnr), query_group)
end
return query_cache.get(query_group, bufnr).cache
end
end
---@param lang string
---@param query_name string
---@return string[]
local function runtime_queries(lang, query_name)
return api.nvim_get_runtime_file(string.format("queries/%s/%s.scm", lang, query_name), true) or {}
end
---@type table<string, table<string, boolean>>
local query_files_cache = {}
---@param lang string
---@param query_name string
---@return boolean
function M.has_query_files(lang, query_name)
if not query_files_cache[lang] then
query_files_cache[lang] = {}
end
if query_files_cache[lang][query_name] == nil then
local files = runtime_queries(lang, query_name)
query_files_cache[lang][query_name] = files and #files > 0
end
return query_files_cache[lang][query_name]
end
do
local mt = {}
mt.__index = function(tbl, key)
if rawget(tbl, key) == nil then
rawset(tbl, key, {})
end
return rawget(tbl, key)
end
-- cache will auto set the table for each lang if it is nil
---@type table<string, table<string, Query>>
local cache = setmetatable({}, mt)
-- Same as `vim.treesitter.query` except will return cached values
---@param lang string
---@param query_name string
function M.get_query(lang, query_name)
if cache[lang][query_name] == nil then
cache[lang][query_name] = ts.get_query(lang, query_name)
end
return cache[lang][query_name]
end
-- Invalidates the query file cache.
--
-- If lang and query_name is both present, will reload for only the lang and query_name.
-- If only lang is present, will reload all query_names for that lang
-- If none are present, will reload everything
---@param lang? string
---@param query_name? string
function M.invalidate_query_cache(lang, query_name)
if lang and query_name then
cache[lang][query_name] = nil
if query_files_cache[lang] then
query_files_cache[lang][query_name] = nil
end
elseif lang and not query_name then
query_files_cache[lang] = nil
for query_name0, _ in pairs(cache[lang]) do
M.invalidate_query_cache(lang, query_name0)
end
elseif not lang and not query_name then
query_files_cache = {}
for lang0, _ in pairs(cache) do
for query_name0, _ in pairs(cache[lang0]) do
M.invalidate_query_cache(lang0, query_name0)
end
end
else
error "Cannot have query_name by itself!"
end
end
end
-- This function is meant for an autocommand and not to be used. Only use if file is a query file.
---@param fname string
function M.invalidate_query_file(fname)
local fnamemodify = vim.fn.fnamemodify
M.invalidate_query_cache(fnamemodify(fname, ":p:h:t"), fnamemodify(fname, ":t:r"))
end
---@class QueryInfo
---@field root TSNode
---@field source integer
---@field start integer
---@field stop integer
---@param bufnr integer
---@param query_name string
---@param root TSNode
---@param root_lang string|nil
---@return Query|nil, QueryInfo|nil
local function prepare_query(bufnr, query_name, root, root_lang)
local buf_lang = parsers.get_buf_lang(bufnr)
if not buf_lang then
return
end
local parser = parsers.get_parser(bufnr, buf_lang)
if not parser then
return
end
if not root then
local first_tree = parser:trees()[1]
if first_tree then
root = first_tree:root()
end
end
if not root then
return
end
local range = { root:range() }
if not root_lang then
local lang_tree = parser:language_for_range(range)
if lang_tree then
root_lang = lang_tree:lang()
end
end
if not root_lang then
return
end
local query = M.get_query(root_lang, query_name)
if not query then
return
end
return query,
{
root = root,
source = bufnr,
start = range[1],
-- The end row is exclusive so we need to add 1 to it.
stop = range[3] + 1,
}
end
-- Given a path (i.e. a List(String)) this functions inserts value at path
---@param object any
---@param path string[]
---@param value any
function M.insert_to_path(object, path, value)
local curr_obj = object
for index = 1, (#path - 1) do
if curr_obj[path[index]] == nil then
curr_obj[path[index]] = {}
end
curr_obj = curr_obj[path[index]]
end
curr_obj[path[#path]] = value
end
---@param query Query
---@param bufnr integer
---@param start_row integer
---@param end_row integer
function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row)
-- A function that splits a string on '.'
---@param to_split string
---@return string[]
local function split(to_split)
local t = {}
for str in string.gmatch(to_split, "([^.]+)") do
table.insert(t, str)
end
return t
end
local matches = query:iter_matches(qnode, bufnr, start_row, end_row, { all = false })
local function iterator()
local pattern, match, metadata = matches()
if pattern ~= nil then
local prepared_match = {}
-- Extract capture names from each match
for id, node in pairs(match) do
local name = query.captures[id] -- name of the capture in the query
if name ~= nil then
local path = split(name .. ".node")
M.insert_to_path(prepared_match, path, node)
local metadata_path = split(name .. ".metadata")
M.insert_to_path(prepared_match, metadata_path, metadata[id])
end
end
-- Add some predicates for testing
---@type string[][] ( TODO: make pred type so this can be pred[])
local preds = query.info.patterns[pattern]
if preds then
for _, pred in pairs(preds) do
-- functions
if pred[1] == "set!" and type(pred[2]) == "string" then
M.insert_to_path(prepared_match, split(pred[2]), pred[3])
end
if pred[1] == "make-range!" and type(pred[2]) == "string" and #pred == 4 then
M.insert_to_path(
prepared_match,
split(pred[2] .. ".node"),
tsrange.TSRange.from_nodes(bufnr, match[pred[3]], match[pred[4]])
)
end
end
end
return prepared_match
end
end
return iterator
end
-- Return all nodes corresponding to a specific capture path (like @definition.var, @reference.type)
-- Works like M.get_references or M.get_scopes except you can choose the capture
-- Can also be a nested capture like @definition.function to get all nodes defining a function.
--
---@param bufnr integer the buffer
---@param captures string|string[]
---@param query_group string the name of query group (highlights or injections for example)
---@param root TSNode|nil node from where to start the search
---@param lang string|nil the language from where to get the captures.
--- Root nodes can have several languages.
---@return table|nil
function M.get_capture_matches(bufnr, captures, query_group, root, lang)
if type(captures) == "string" then
captures = { captures }
end
local strip_captures = {} ---@type string[]
for i, capture in ipairs(captures) do
if capture:sub(1, 1) ~= "@" then
error 'Captures must start with "@"'
return
end
-- Remove leading "@".
strip_captures[i] = capture:sub(2)
end
local matches = {}
for match in M.iter_group_results(bufnr, query_group, root, lang) do
for _, capture in ipairs(strip_captures) do
local insert = utils.get_at_path(match, capture)
if insert then
table.insert(matches, insert)
end
end
end
return matches
end
function M.iter_captures(bufnr, query_name, root, lang)
local query, params = prepare_query(bufnr, query_name, root, lang)
if not query then
return EMPTY_ITER
end
assert(params)
local iter = query:iter_captures(params.root, params.source, params.start, params.stop)
local function wrapped_iter()
local id, node, metadata = iter()
if not id then
return
end
local name = query.captures[id]
if string.sub(name, 1, 1) == "_" then
return wrapped_iter()
end
return name, node, metadata
end
return wrapped_iter
end
---@param bufnr integer
---@param capture_string string
---@param query_group string
---@param filter_predicate fun(match: table): boolean
---@param scoring_function fun(match: table): number
---@param root TSNode
---@return table|unknown
function M.find_best_match(bufnr, capture_string, query_group, filter_predicate, scoring_function, root)
if string.sub(capture_string, 1, 1) == "@" then
--remove leading "@"
capture_string = string.sub(capture_string, 2)
end
local best ---@type table|nil
local best_score ---@type number
for maybe_match in M.iter_group_results(bufnr, query_group, root) do
local match = utils.get_at_path(maybe_match, capture_string)
if match and filter_predicate(match) then
local current_score = scoring_function(match)
if not best then
best = match
best_score = current_score
end
if current_score > best_score then
best = match
best_score = current_score
end
end
end
return best
end
---Iterates matches from a query file.
---@param bufnr integer the buffer
---@param query_group string the query file to use
---@param root TSNode the root node
---@param root_lang? string the root node lang, if known
function M.iter_group_results(bufnr, query_group, root, root_lang)
local query, params = prepare_query(bufnr, query_group, root, root_lang)
if not query then
return EMPTY_ITER
end
assert(params)
return M.iter_prepared_matches(query, params.root, params.source, params.start, params.stop)
end
function M.collect_group_results(bufnr, query_group, root, lang)
local matches = {}
for prepared_match in M.iter_group_results(bufnr, query_group, root, lang) do
table.insert(matches, prepared_match)
end
return matches
end
---@alias CaptureResFn function(string, LanguageTree, LanguageTree): string, string
-- Same as get_capture_matches except this will recursively get matches for every language in the tree.
---@param bufnr integer The buffer
---@param capture_or_fn string|CaptureResFn The capture to get. If a function is provided then that
--- function will be used to resolve both the capture and query argument.
--- The function can return `nil` to ignore that tree.
---@param query_type string? The query to get the capture from. This is ignored if a function is provided
--- for the capture argument.
---@return table[]
function M.get_capture_matches_recursively(bufnr, capture_or_fn, query_type)
---@type CaptureResFn
local type_fn
if type(capture_or_fn) == "function" then
type_fn = capture_or_fn
else
type_fn = function(_, _, _)
return capture_or_fn, query_type
end
end
local parser = parsers.get_parser(bufnr)
local matches = {}
if parser then
parser:for_each_tree(function(tree, lang_tree)
local lang = lang_tree:lang()
local capture, type_ = type_fn(lang, tree, lang_tree)
if capture then
vim.list_extend(matches, M.get_capture_matches(bufnr, capture, type_, tree:root(), lang) or {})
end
end)
end
return matches
end
return M

View file

@ -1,167 +0,0 @@
local query = require "vim.treesitter.query"
local html_script_type_languages = {
["importmap"] = "json",
["module"] = "javascript",
["application/ecmascript"] = "javascript",
["text/ecmascript"] = "javascript",
}
local non_filetype_match_injection_language_aliases = {
ex = "elixir",
pl = "perl",
sh = "bash",
uxn = "uxntal",
ts = "typescript",
}
-- compatibility shim for breaking change on nightly/0.11
local opts = vim.fn.has "nvim-0.10" == 1 and { force = true, all = false } or true
local function get_parser_from_markdown_info_string(injection_alias)
local match = vim.filetype.match { filename = "a." .. injection_alias }
return match or non_filetype_match_injection_language_aliases[injection_alias] or injection_alias
end
local function error(str)
vim.api.nvim_err_writeln(str)
end
local function valid_args(name, pred, count, strict_count)
local arg_count = #pred - 1
if strict_count then
if arg_count ~= count then
error(string.format("%s must have exactly %d arguments", name, count))
return false
end
elseif arg_count < count then
error(string.format("%s must have at least %d arguments", name, count))
return false
end
return true
end
---@param match (TSNode|nil)[]
---@param _pattern string
---@param _bufnr integer
---@param pred string[]
---@return boolean|nil
query.add_predicate("nth?", function(match, _pattern, _bufnr, pred)
if not valid_args("nth?", pred, 2, true) then
return
end
local node = match[pred[2]] ---@type TSNode
local n = tonumber(pred[3])
if node and node:parent() and node:parent():named_child_count() > n then
return node:parent():named_child(n) == node
end
return false
end, opts)
---@param match (TSNode|nil)[]
---@param _pattern string
---@param bufnr integer
---@param pred string[]
---@return boolean|nil
query.add_predicate("is?", function(match, _pattern, bufnr, pred)
if not valid_args("is?", pred, 2) then
return
end
-- Avoid circular dependencies
local locals = require "nvim-treesitter.locals"
local node = match[pred[2]]
local types = { unpack(pred, 3) }
if not node then
return true
end
local _, _, kind = locals.find_definition(node, bufnr)
return vim.tbl_contains(types, kind)
end, opts)
---@param match (TSNode|nil)[]
---@param _pattern string
---@param _bufnr integer
---@param pred string[]
---@return boolean|nil
query.add_predicate("kind-eq?", function(match, _pattern, _bufnr, pred)
if not valid_args(pred[1], pred, 2) then
return
end
local node = match[pred[2]]
local types = { unpack(pred, 3) }
if not node then
return true
end
return vim.tbl_contains(types, node:type())
end, opts)
---@param match (TSNode|nil)[]
---@param _ string
---@param bufnr integer
---@param pred string[]
---@return boolean|nil
query.add_directive("set-lang-from-mimetype!", function(match, _, bufnr, pred, metadata)
local capture_id = pred[2]
local node = match[capture_id]
if not node then
return
end
local type_attr_value = vim.treesitter.get_node_text(node, bufnr)
local configured = html_script_type_languages[type_attr_value]
if configured then
metadata["injection.language"] = configured
else
local parts = vim.split(type_attr_value, "/", {})
metadata["injection.language"] = parts[#parts]
end
end, opts)
---@param match (TSNode|nil)[]
---@param _ string
---@param bufnr integer
---@param pred string[]
---@return boolean|nil
query.add_directive("set-lang-from-info-string!", function(match, _, bufnr, pred, metadata)
local capture_id = pred[2]
local node = match[capture_id]
if not node then
return
end
local injection_alias = vim.treesitter.get_node_text(node, bufnr):lower()
metadata["injection.language"] = get_parser_from_markdown_info_string(injection_alias)
end, opts)
-- Just avoid some annoying warnings for this directive
query.add_directive("make-range!", function() end, opts)
--- transform node text to lower case (e.g., to make @injection.language case insensitive)
---
---@param match (TSNode|nil)[]
---@param _ string
---@param bufnr integer
---@param pred string[]
---@return boolean|nil
query.add_directive("downcase!", function(match, _, bufnr, pred, metadata)
local id = pred[2]
local node = match[id]
if not node then
return
end
local text = vim.treesitter.get_node_text(node, bufnr, { metadata = metadata[id] }) or ""
if not metadata[id] then
metadata[id] = {}
end
metadata[id].text = string.lower(text)
end, opts)

View file

@ -1,368 +0,0 @@
local fn = vim.fn
local utils = require "nvim-treesitter.utils"
local uv = vim.uv or vim.loop
-- Convert path for cmd.exe on Windows.
-- This is needed when vim.opt.shellslash is in use.
---@param p string
---@return string
local function cmdpath(p)
if vim.opt.shellslash:get() then
local r = p:gsub("/", "\\")
return r
else
return p
end
end
local M = {}
-- Returns the mkdir command based on the OS
---@param directory string
---@param cwd string
---@param info_msg string
---@return table
function M.select_mkdir_cmd(directory, cwd, info_msg)
if fn.has "win32" == 1 then
return {
cmd = "cmd",
opts = {
args = { "/C", "mkdir", cmdpath(directory) },
cwd = cwd,
},
info = info_msg,
err = "Could not create " .. directory,
}
else
return {
cmd = "mkdir",
opts = {
args = { directory },
cwd = cwd,
},
info = info_msg,
err = "Could not create " .. directory,
}
end
end
-- Returns the remove command based on the OS
---@param file string
---@param info_msg string
---@return table
function M.select_rm_file_cmd(file, info_msg)
if fn.has "win32" == 1 then
return {
cmd = "cmd",
opts = {
args = { "/C", "if", "exist", cmdpath(file), "del", cmdpath(file) },
},
info = info_msg,
err = "Could not delete " .. file,
}
else
return {
cmd = "rm",
opts = {
args = { file },
},
info = info_msg,
err = "Could not delete " .. file,
}
end
end
---@param executables string[]
---@return string|nil
function M.select_executable(executables)
return vim.tbl_filter(function(c) ---@param c string
return c ~= vim.NIL and fn.executable(c) == 1
end, executables)[1]
end
-- Returns the compiler arguments based on the compiler and OS
---@param repo InstallInfo
---@param compiler string
---@return string[]
function M.select_compiler_args(repo, compiler)
if string.match(compiler, "cl$") or string.match(compiler, "cl.exe$") then
return {
"/Fe:",
"parser.so",
"/Isrc",
repo.files,
"-Os",
"/std:c11",
"/utf-8",
"/LD",
}
elseif string.match(compiler, "zig$") or string.match(compiler, "zig.exe$") then
return {
"c++",
"-o",
"parser.so",
repo.files,
"-lc",
"-Isrc",
"-shared",
"-Os",
"-std=c11",
}
else
local args = {
"-o",
"parser.so",
"-I./src",
repo.files,
"-Os",
"-std=c11",
}
if fn.has "mac" == 1 then
table.insert(args, "-bundle")
else
table.insert(args, "-shared")
end
if
#vim.tbl_filter(function(file) ---@param file string
local ext = vim.fn.fnamemodify(file, ":e")
return ext == "cc" or ext == "cpp" or ext == "cxx"
end, repo.files) > 0
then
table.insert(args, "-lstdc++")
end
if fn.has "win32" == 0 then
table.insert(args, "-fPIC")
end
return args
end
end
-- Returns the compile command based on the OS and user options
---@param repo InstallInfo
---@param cc string
---@param compile_location string
---@return Command
function M.select_compile_command(repo, cc, compile_location)
local make = M.select_executable { "gmake", "make" }
if
string.match(cc, "cl$")
or string.match(cc, "cl.exe$")
or not repo.use_makefile
or fn.has "win32" == 1
or not make
then
return {
cmd = cc,
info = "Compiling...",
err = "Error during compilation",
opts = {
args = require("nvim-treesitter.compat").flatten(M.select_compiler_args(repo, cc)),
cwd = compile_location,
},
}
else
return {
cmd = make,
info = "Compiling...",
err = "Error during compilation",
opts = {
args = {
"--makefile=" .. utils.join_path(utils.get_package_path(), "scripts", "compile_parsers.makefile"),
"CC=" .. cc,
"CXX_STANDARD=" .. (repo.cxx_standard or "c++14"),
},
cwd = compile_location,
},
}
end
end
-- Returns the remove command based on the OS
---@param cache_folder string
---@param project_name string
---@return Command
function M.select_install_rm_cmd(cache_folder, project_name)
if fn.has "win32" == 1 then
local dir = cache_folder .. "\\" .. project_name
return {
cmd = "cmd",
opts = {
args = { "/C", "if", "exist", cmdpath(dir), "rmdir", "/s", "/q", cmdpath(dir) },
},
}
else
return {
cmd = "rm",
opts = {
args = { "-rf", cache_folder .. "/" .. project_name },
},
}
end
end
-- Returns the move command based on the OS
---@param from string
---@param to string
---@param cwd string
---@return Command
function M.select_mv_cmd(from, to, cwd)
if fn.has "win32" == 1 then
return {
cmd = "cmd",
opts = {
args = { "/C", "move", "/Y", cmdpath(from), cmdpath(to) },
cwd = cwd,
},
}
else
return {
cmd = "mv",
opts = {
args = { "-f", from, to },
cwd = cwd,
},
}
end
end
---@param repo InstallInfo
---@param project_name string
---@param cache_folder string
---@param revision string|nil
---@param prefer_git boolean
---@return table
function M.select_download_commands(repo, project_name, cache_folder, revision, prefer_git)
local can_use_tar = vim.fn.executable "tar" == 1 and vim.fn.executable "curl" == 1
local is_github = repo.url:find("github.com", 1, true)
local is_gitlab = repo.url:find("gitlab.com", 1, true)
revision = revision or repo.branch or "master"
if can_use_tar and (is_github or is_gitlab) and not prefer_git then
local path_sep = utils.get_path_sep()
local url = repo.url:gsub(".git$", "")
local folder_rev = revision
if is_github and revision:match "^v%d" then
folder_rev = revision:sub(2)
end
return {
M.select_install_rm_cmd(cache_folder, project_name .. "-tmp"),
{
cmd = "curl",
info = "Downloading " .. project_name .. "...",
err = "Error during download, please verify your internet connection",
opts = {
args = {
"--silent",
"--show-error",
"-L", -- follow redirects
is_github and url .. "/archive/" .. revision .. ".tar.gz"
or url .. "/-/archive/" .. revision .. "/" .. project_name .. "-" .. revision .. ".tar.gz",
"--output",
project_name .. ".tar.gz",
},
cwd = cache_folder,
},
},
M.select_mkdir_cmd(project_name .. "-tmp", cache_folder, "Creating temporary directory"),
{
cmd = "tar",
info = "Extracting " .. project_name .. "...",
err = "Error during tarball extraction.",
opts = {
args = {
"-xvzf",
project_name .. ".tar.gz",
"-C",
project_name .. "-tmp",
},
cwd = cache_folder,
},
},
M.select_rm_file_cmd(cache_folder .. path_sep .. project_name .. ".tar.gz"),
M.select_mv_cmd(
utils.join_path(project_name .. "-tmp", url:match "[^/]-$" .. "-" .. folder_rev),
project_name,
cache_folder
),
M.select_install_rm_cmd(cache_folder, project_name .. "-tmp"),
}
else
local git_folder = utils.join_path(cache_folder, project_name)
local clone_error = "Error during download, please verify your internet connection"
-- Running `git clone` or `git checkout` while running under Git (such as
-- editing a `git commit` message) will likely fail to install parsers
-- (such as 'gitcommit') and can also corrupt the index file of the current
-- Git repository. Check for typical git environment variables and abort if found.
for _, k in pairs {
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
"GIT_CEILING_DIRECTORIES",
"GIT_DIR",
"GIT_INDEX",
"GIT_INDEX_FILE",
"GIT_OBJECT_DIRECTORY",
"GIT_PREFIX",
"GIT_WORK_TREE",
} do
if uv.os_getenv(k) then
vim.api.nvim_err_writeln(
string.format(
"Cannot install %s with git in an active git session. Exit the session and run ':TSInstall %s' manually",
project_name,
project_name
)
)
return {}
end
end
return {
{
cmd = "git",
info = "Downloading " .. project_name .. "...",
err = clone_error,
opts = {
args = {
"clone",
repo.url,
project_name,
"--filter=blob:none",
},
cwd = cache_folder,
},
},
{
cmd = "git",
info = "Checking out locked revision",
err = "Error while checking out revision",
opts = {
args = {
"checkout",
revision,
},
cwd = git_folder,
},
},
}
end
end
---@param dir string
---@param command string
---@return string command
function M.make_directory_change_for_command(dir, command)
if fn.has "win32" == 1 then
if string.find(vim.o.shell, "cmd") ~= nil then
return string.format("pushd %s & %s", cmdpath(dir), command)
else
return string.format("pushd %s ; %s", cmdpath(dir), command)
end
else
return string.format("cd %s;\n%s", dir, command)
end
end
return M

View file

@ -1,53 +0,0 @@
local parsers = require "nvim-treesitter.parsers"
local ts_utils = require "nvim-treesitter.ts_utils"
local M = {}
-- Trim spaces and opening brackets from end
local transform_line = function(line)
return line:gsub("%s*[%[%(%{]*%s*$", "")
end
function M.statusline(opts)
if not parsers.has_parser() then
return
end
local options = opts or {}
if type(opts) == "number" then
options = { indicator_size = opts }
end
local bufnr = options.bufnr or 0
local indicator_size = options.indicator_size or 100
local type_patterns = options.type_patterns or { "class", "function", "method" }
local transform_fn = options.transform_fn or transform_line
local separator = options.separator or " -> "
local allow_duplicates = options.allow_duplicates or false
local current_node = ts_utils.get_node_at_cursor()
if not current_node then
return ""
end
local lines = {}
local expr = current_node
while expr do
local line = ts_utils._get_line_for_node(expr, type_patterns, transform_fn, bufnr)
if line ~= "" then
if allow_duplicates or not vim.tbl_contains(lines, line) then
table.insert(lines, 1, line)
end
end
expr = expr:parent()
end
local text = table.concat(lines, separator)
local text_len = #text
if text_len > indicator_size then
return "..." .. text:sub(text_len - indicator_size, text_len)
end
return text
end
return M

View file

@ -1,482 +0,0 @@
local api = vim.api
local parsers = require "nvim-treesitter.parsers"
local utils = require "nvim-treesitter.utils"
local ts = vim.treesitter
local M = {}
local function get_node_text(node, bufnr)
bufnr = bufnr or api.nvim_get_current_buf()
if not node then
return {}
end
-- We have to remember that end_col is end-exclusive
local start_row, start_col, end_row, end_col = ts.get_node_range(node)
if start_row ~= end_row then
local lines = api.nvim_buf_get_lines(bufnr, start_row, end_row + 1, false)
if next(lines) == nil then
return {}
end
lines[1] = string.sub(lines[1], start_col + 1)
-- end_row might be just after the last line. In this case the last line is not truncated.
if #lines == end_row - start_row + 1 then
lines[#lines] = string.sub(lines[#lines], 1, end_col)
end
return lines
else
local line = api.nvim_buf_get_lines(bufnr, start_row, start_row + 1, false)[1]
-- If line is nil then the line is empty
return line and { string.sub(line, start_col + 1, end_col) } or {}
end
end
---@private
---@param node TSNode
---@param type_patterns string[]
---@param transform_fn fun(line: string): string
---@param bufnr integer
---@return string
function M._get_line_for_node(node, type_patterns, transform_fn, bufnr)
local node_type = node:type()
local is_valid = false
for _, rgx in ipairs(type_patterns) do
if node_type:find(rgx) then
is_valid = true
break
end
end
if not is_valid then
return ""
end
local line = transform_fn(vim.trim(get_node_text(node, bufnr)[1] or ""), node)
-- Escape % to avoid statusline to evaluate content as expression
return line:gsub("%%", "%%%%")
end
-- Gets the actual text content of a node
-- @deprecated Use vim.treesitter.get_node_text
-- @param node the node to get the text from
-- @param bufnr the buffer containing the node
-- @return list of lines of text of the node
function M.get_node_text(node, bufnr)
vim.notify_once(
"nvim-treesitter.ts_utils.get_node_text is deprecated: use vim.treesitter.get_node_text",
vim.log.levels.WARN
)
return get_node_text(node, bufnr)
end
-- Determines whether a node is the parent of another
-- @param dest the possible parent
-- @param source the possible child node
function M.is_parent(dest, source)
if not (dest and source) then
return false
end
local current = source
while current ~= nil do
if current == dest then
return true
end
current = current:parent()
end
return false
end
-- Get next node with same parent
---@param node TSNode
---@param allow_switch_parents? boolean allow switching parents if last node
---@param allow_next_parent? boolean allow next parent if last node and next parent without children
function M.get_next_node(node, allow_switch_parents, allow_next_parent)
local destination_node ---@type TSNode
local parent = node:parent()
if not parent then
return
end
local found_pos = 0
for i = 0, parent:named_child_count() - 1, 1 do
if parent:named_child(i) == node then
found_pos = i
break
end
end
if parent:named_child_count() > found_pos + 1 then
destination_node = parent:named_child(found_pos + 1)
elseif allow_switch_parents then
local next_node = M.get_next_node(node:parent())
if next_node and next_node:named_child_count() > 0 then
destination_node = next_node:named_child(0)
elseif next_node and allow_next_parent then
destination_node = next_node
end
end
return destination_node
end
-- Get previous node with same parent
---@param node TSNode
---@param allow_switch_parents? boolean allow switching parents if first node
---@param allow_previous_parent? boolean allow previous parent if first node and previous parent without children
function M.get_previous_node(node, allow_switch_parents, allow_previous_parent)
local destination_node ---@type TSNode
local parent = node:parent()
if not parent then
return
end
local found_pos = 0
for i = 0, parent:named_child_count() - 1, 1 do
if parent:named_child(i) == node then
found_pos = i
break
end
end
if 0 < found_pos then
destination_node = parent:named_child(found_pos - 1)
elseif allow_switch_parents then
local previous_node = M.get_previous_node(node:parent())
if previous_node and previous_node:named_child_count() > 0 then
destination_node = previous_node:named_child(previous_node:named_child_count() - 1)
elseif previous_node and allow_previous_parent then
destination_node = previous_node
end
end
return destination_node
end
function M.get_named_children(node)
local nodes = {} ---@type TSNode[]
for i = 0, node:named_child_count() - 1, 1 do
nodes[i + 1] = node:named_child(i)
end
return nodes
end
function M.get_node_at_cursor(winnr, ignore_injected_langs)
winnr = winnr or 0
local cursor = api.nvim_win_get_cursor(winnr)
local cursor_range = { cursor[1] - 1, cursor[2] }
local buf = vim.api.nvim_win_get_buf(winnr)
local root_lang_tree = parsers.get_parser(buf)
if not root_lang_tree then
return
end
local root ---@type TSNode|nil
if ignore_injected_langs then
for _, tree in pairs(root_lang_tree:trees()) do
local tree_root = tree:root()
if tree_root and ts.is_in_node_range(tree_root, cursor_range[1], cursor_range[2]) then
root = tree_root
break
end
end
else
root = M.get_root_for_position(cursor_range[1], cursor_range[2], root_lang_tree)
end
if not root then
return
end
return root:named_descendant_for_range(cursor_range[1], cursor_range[2], cursor_range[1], cursor_range[2])
end
function M.get_root_for_position(line, col, root_lang_tree)
if not root_lang_tree then
if not parsers.has_parser() then
return
end
root_lang_tree = parsers.get_parser()
end
local lang_tree = root_lang_tree:language_for_range { line, col, line, col }
while true do
for _, tree in pairs(lang_tree:trees()) do
local root = tree:root()
if root and ts.is_in_node_range(root, line, col) then
return root, tree, lang_tree
end
end
if lang_tree == root_lang_tree then
break
end
-- This case can happen when the cursor is at the start of a line that ends a injected region,
-- e.g., the first `]` in the following lua code:
-- ```
-- vim.cmd[[
-- ]]
-- ```
lang_tree = lang_tree:parent() -- NOTE: parent() method is private
end
-- This isn't a likely scenario, since the position must belong to a tree somewhere.
return nil, nil, lang_tree
end
---comment
---@param node TSNode
---@return TSNode result
function M.get_root_for_node(node)
local parent = node
local result = node
while parent ~= nil do
result = parent
parent = result:parent()
end
return result
end
function M.highlight_node(node, buf, hl_namespace, hl_group)
if not node then
return
end
M.highlight_range({ node:range() }, buf, hl_namespace, hl_group)
end
-- Get a compatible vim range (1 index based) from a TS node range.
--
-- TS nodes start with 0 and the end col is ending exclusive.
-- They also treat a EOF/EOL char as a char ending in the first
-- col of the next row.
---comment
---@param range integer[]
---@param buf integer|nil
---@return integer, integer, integer, integer
function M.get_vim_range(range, buf)
---@type integer, integer, integer, integer
local srow, scol, erow, ecol = unpack(range)
srow = srow + 1
scol = scol + 1
erow = erow + 1
if ecol == 0 then
-- Use the value of the last col of the previous row instead.
erow = erow - 1
if not buf or buf == 0 then
ecol = vim.fn.col { erow, "$" } - 1
else
ecol = #api.nvim_buf_get_lines(buf, erow - 1, erow, false)[1]
end
ecol = math.max(ecol, 1)
end
return srow, scol, erow, ecol
end
function M.highlight_range(range, buf, hl_namespace, hl_group)
---@type integer, integer, integer, integer
local start_row, start_col, end_row, end_col = unpack(range)
---@diagnostic disable-next-line: missing-parameter
vim.highlight.range(buf, hl_namespace, hl_group, { start_row, start_col }, { end_row, end_col })
end
-- Set visual selection to node
-- @param selection_mode One of "charwise" (default) or "v", "linewise" or "V",
-- "blockwise" or "<C-v>" (as a string with 5 characters or a single character)
function M.update_selection(buf, node, selection_mode)
local start_row, start_col, end_row, end_col = M.get_vim_range({ ts.get_node_range(node) }, buf)
local v_table = { charwise = "v", linewise = "V", blockwise = "<C-v>" }
selection_mode = selection_mode or "charwise"
-- Normalise selection_mode
if vim.tbl_contains(vim.tbl_keys(v_table), selection_mode) then
selection_mode = v_table[selection_mode]
end
-- enter visual mode if normal or operator-pending (no) mode
-- Why? According to https://learnvimscriptthehardway.stevelosh.com/chapters/15.html
-- If your operator-pending mapping ends with some text visually selected, Vim will operate on that text.
-- Otherwise, Vim will operate on the text between the original cursor position and the new position.
local mode = api.nvim_get_mode()
if mode.mode ~= selection_mode then
-- Call to `nvim_replace_termcodes()` is needed for sending appropriate command to enter blockwise mode
selection_mode = vim.api.nvim_replace_termcodes(selection_mode, true, true, true)
api.nvim_cmd({ cmd = "normal", bang = true, args = { selection_mode } }, {})
end
api.nvim_win_set_cursor(0, { start_row, start_col - 1 })
vim.cmd "normal! o"
api.nvim_win_set_cursor(0, { end_row, end_col - 1 })
end
-- Byte length of node range
---@param node TSNode
---@return number
function M.node_length(node)
local _, _, start_byte = node:start()
local _, _, end_byte = node:end_()
return end_byte - start_byte
end
---@deprecated Use `vim.treesitter.is_in_node_range()` instead
function M.is_in_node_range(node, line, col)
vim.notify_once(
"nvim-treesitter.ts_utils.is_in_node_range is deprecated: use vim.treesitter.is_in_node_range",
vim.log.levels.WARN
)
return ts.is_in_node_range(node, line, col)
end
---@deprecated Use `vim.treesitter.get_node_range()` instead
function M.get_node_range(node_or_range)
vim.notify_once(
"nvim-treesitter.ts_utils.get_node_range is deprecated: use vim.treesitter.get_node_range",
vim.log.levels.WARN
)
return ts.get_node_range(node_or_range)
end
---@param node TSNode
---@return table
function M.node_to_lsp_range(node)
local start_line, start_col, end_line, end_col = ts.get_node_range(node)
local rtn = {}
rtn.start = { line = start_line, character = start_col }
rtn["end"] = { line = end_line, character = end_col }
return rtn
end
-- Memoizes a function based on the buffer tick of the provided bufnr.
-- The cache entry is cleared when the buffer is detached to avoid memory leaks.
-- The options argument is a table with two optional values:
-- - bufnr: extracts a bufnr from the given arguments.
-- - key: extracts the cache key from the given arguments.
---@param fn function the fn to memoize, taking the buffer as first argument
---@param options? {bufnr: integer?, key: string|fun(...): string?} the memoization options
---@return function: a memoized function
function M.memoize_by_buf_tick(fn, options)
options = options or {}
---@type table<string, {result: any, last_tick: integer}>
local cache = setmetatable({}, { __mode = "kv" })
local bufnr_fn = utils.to_func(options.bufnr or utils.identity)
local key_fn = utils.to_func(options.key or utils.identity)
return function(...)
local bufnr = bufnr_fn(...)
local key = key_fn(...)
local tick = api.nvim_buf_get_changedtick(bufnr)
if cache[key] then
if cache[key].last_tick == tick then
return cache[key].result
end
else
local function detach_handler()
cache[key] = nil
end
-- Clean up logic only!
api.nvim_buf_attach(bufnr, false, {
on_detach = detach_handler,
on_reload = detach_handler,
})
end
cache[key] = {
result = fn(...),
last_tick = tick,
}
return cache[key].result
end
end
function M.swap_nodes(node_or_range1, node_or_range2, bufnr, cursor_to_second)
if not node_or_range1 or not node_or_range2 then
return
end
local range1 = M.node_to_lsp_range(node_or_range1)
local range2 = M.node_to_lsp_range(node_or_range2)
local text1 = get_node_text(node_or_range1, bufnr)
local text2 = get_node_text(node_or_range2, bufnr)
local edit1 = { range = range1, newText = table.concat(text2, "\n") }
local edit2 = { range = range2, newText = table.concat(text1, "\n") }
bufnr = bufnr == 0 and vim.api.nvim_get_current_buf() or bufnr
vim.lsp.util.apply_text_edits({ edit1, edit2 }, bufnr, "utf-8")
if cursor_to_second then
utils.set_jump()
local char_delta = 0
local line_delta = 0
if
range1["end"].line < range2.start.line
or (range1["end"].line == range2.start.line and range1["end"].character <= range2.start.character)
then
line_delta = #text2 - #text1
end
if range1["end"].line == range2.start.line and range1["end"].character <= range2.start.character then
if line_delta ~= 0 then
--- why?
--correction_after_line_change = -range2.start.character
--text_now_before_range2 = #(text2[#text2])
--space_between_ranges = range2.start.character - range1["end"].character
--char_delta = correction_after_line_change + text_now_before_range2 + space_between_ranges
--- Equivalent to:
char_delta = #text2[#text2] - range1["end"].character
-- add range1.start.character if last line of range1 (now text2) does not start at 0
if range1.start.line == range2.start.line + line_delta then
char_delta = char_delta + range1.start.character
end
else
char_delta = #text2[#text2] - #text1[#text1]
end
end
api.nvim_win_set_cursor(
api.nvim_get_current_win(),
{ range2.start.line + 1 + line_delta, range2.start.character + char_delta }
)
end
end
function M.goto_node(node, goto_end, avoid_set_jump)
if not node then
return
end
if not avoid_set_jump then
utils.set_jump()
end
local range = { M.get_vim_range { node:range() } }
---@type table<number>
local position
if not goto_end then
position = { range[1], range[2] }
else
position = { range[3], range[4] }
end
-- Enter visual mode if we are in operator pending mode
-- If we don't do this, it will miss the last character.
local mode = vim.api.nvim_get_mode()
if mode.mode == "no" then
vim.cmd "normal! v"
end
-- Position is 1, 0 indexed.
api.nvim_win_set_cursor(0, { position[1], position[2] - 1 })
end
return M

View file

@ -1,154 +0,0 @@
local M = {}
local TSRange = {}
TSRange.__index = TSRange
local api = vim.api
local ts_utils = require "nvim-treesitter.ts_utils"
local parsers = require "nvim-treesitter.parsers"
local function get_byte_offset(buf, row, col)
return api.nvim_buf_get_offset(buf, row) + vim.fn.byteidx(api.nvim_buf_get_lines(buf, row, row + 1, false)[1], col)
end
function TSRange.new(buf, start_row, start_col, end_row, end_col)
return setmetatable({
start_pos = { start_row, start_col, get_byte_offset(buf, start_row, start_col) },
end_pos = { end_row, end_col, get_byte_offset(buf, end_row, end_col) },
buf = buf,
[1] = start_row,
[2] = start_col,
[3] = end_row,
[4] = end_col,
}, TSRange)
end
function TSRange.from_nodes(buf, start_node, end_node)
TSRange.__index = TSRange
local start_pos = start_node and { start_node:start() } or { end_node:start() }
local end_pos = end_node and { end_node:end_() } or { start_node:end_() }
return setmetatable({
start_pos = { start_pos[1], start_pos[2], start_pos[3] },
end_pos = { end_pos[1], end_pos[2], end_pos[3] },
buf = buf,
[1] = start_pos[1],
[2] = start_pos[2],
[3] = end_pos[1],
[4] = end_pos[2],
}, TSRange)
end
function TSRange.from_table(buf, range)
return setmetatable({
start_pos = { range[1], range[2], get_byte_offset(buf, range[1], range[2]) },
end_pos = { range[3], range[4], get_byte_offset(buf, range[3], range[4]) },
buf = buf,
[1] = range[1],
[2] = range[2],
[3] = range[3],
[4] = range[4],
}, TSRange)
end
function TSRange:parent()
local root_lang_tree = parsers.get_parser(self.buf)
local root = ts_utils.get_root_for_position(self[1], self[2], root_lang_tree)
return root
and root:named_descendant_for_range(self.start_pos[1], self.start_pos[2], self.end_pos[1], self.end_pos[2])
or nil
end
function TSRange:field() end
function TSRange:child_count()
return #self:collect_children()
end
function TSRange:named_child_count()
return #self:collect_children(function(c)
return c:named()
end)
end
function TSRange:iter_children()
local raw_iterator = self:parent().iter_children()
return function()
while true do
local node = raw_iterator()
if not node then
return
end
local _, _, start_byte = node:start()
local _, _, end_byte = node:end_()
if start_byte >= self.start_pos[3] and end_byte <= self.end_pos[3] then
return node
end
end
end
end
function TSRange:collect_children(filter_fun)
local children = {}
for _, c in self:iter_children() do
if not filter_fun or filter_fun(c) then
table.insert(children, c)
end
end
return children
end
function TSRange:child(index)
return self:collect_children()[index + 1]
end
function TSRange:named_child(index)
return self:collect_children(function(c)
return c.named()
end)[index + 1]
end
function TSRange:start()
return unpack(self.start_pos)
end
function TSRange:end_()
return unpack(self.end_pos)
end
function TSRange:range()
return self.start_pos[1], self.start_pos[2], self.end_pos[1], self.end_pos[2]
end
function TSRange:type()
return "nvim-treesitter-range"
end
function TSRange:symbol()
return -1
end
function TSRange:named()
return false
end
function TSRange:missing()
return false
end
function TSRange:has_error()
return #self:collect_children(function(c)
return c:has_error()
end) > 0 and true or false
end
function TSRange:sexpr()
return table.concat(
vim.tbl_map(function(c)
return c:sexpr()
end, self:collect_children()),
" "
)
end
M.TSRange = TSRange
return M

View file

@ -0,0 +1,20 @@
local M = {}
--- @param filename string
--- @return string
function M.read_file(filename)
local file = assert(io.open(filename, 'r'))
local r = file:read('*a')
file:close()
return r
end
--- @param filename string
--- @param content string
function M.write_file(filename, content)
local file = assert(io.open(filename, 'w'))
file:write(content)
file:close()
end
return M

View file

@ -1,237 +0,0 @@
local api = vim.api
local fn = vim.fn
local luv = vim.loop
local M = {}
-- Wrapper around vim.notify with common options set.
---@param msg string
---@param log_level number|nil
---@param opts table|nil
function M.notify(msg, log_level, opts)
local default_opts = { title = "nvim-treesitter" }
vim.notify(msg, log_level, vim.tbl_extend("force", default_opts, opts or {}))
end
-- Returns the system-specific path separator.
---@return string
function M.get_path_sep()
return (fn.has "win32" == 1 and not vim.opt.shellslash:get()) and "\\" or "/"
end
-- Returns a function that joins the given arguments with separator. Arguments
-- can't be nil. Example:
--
--[[
print(M.generate_join(" ")("foo", "bar"))
--]]
--prints "foo bar"
---@param separator string
---@return fun(...: string): string
function M.generate_join(separator)
return function(...)
return table.concat({ ... }, separator)
end
end
M.join_path = M.generate_join(M.get_path_sep())
M.join_space = M.generate_join " "
---@class Command
---@field run function
---@field f_args string
---@field args string
-- Define user defined vim command which calls nvim-treesitter module function
-- - If module name is 'mod', it should be defined in hierarchy 'nvim-treesitter.mod'
-- - A table with name 'commands' should be defined in 'mod' which needs to be passed as
-- the commands param of this function
--
---@param mod string Name of the module that resides in the hierarchy - nvim-treesitter.module
---@param commands table<string, Command> Command list for the module
--- - {command_name} Name of the vim user defined command, Keys:
--- - {run}: (function) callback function that needs to be executed
--- - {f_args}: (string, default <f-args>)
--- - type of arguments that needs to be passed to the vim command
--- - {args}: (string, optional)
--- - vim command attributes
---
---* @example
--- If module is nvim-treesitter.custom_mod
--- <pre>
--- M.commands = {
--- custom_command = {
--- run = M.module_function,
--- f_args = "<f-args>",
--- args = {
--- "-range"
--- }
--- }
--- }
---
--- utils.setup_commands("custom_mod", require("nvim-treesitter.custom_mod").commands)
--- </pre>
---
--- Will generate command :
--- <pre>
--- command! -range custom_command \
--- lua require'nvim-treesitter.custom_mod'.commands.custom_command['run<bang>'](<f-args>)
--- </pre>
function M.setup_commands(mod, commands)
for command_name, def in pairs(commands) do
local f_args = def.f_args or "<f-args>"
local call_fn =
string.format("lua require'nvim-treesitter.%s'.commands.%s['run<bang>'](%s)", mod, command_name, f_args)
local parts = require("nvim-treesitter.compat").flatten {
"command!",
"-bar",
def.args,
command_name,
call_fn,
}
api.nvim_command(table.concat(parts, " "))
end
end
---@param dir string
---@param create_err string
---@param writeable_err string
---@return string|nil, string|nil
function M.create_or_reuse_writable_dir(dir, create_err, writeable_err)
create_err = create_err or M.join_space("Could not create dir '", dir, "': ")
writeable_err = writeable_err or M.join_space("Invalid rights, '", dir, "' should be read/write")
-- Try creating and using parser_dir if it doesn't exist
if not luv.fs_stat(dir) then
local ok, error = pcall(vim.fn.mkdir, dir, "p", "0755")
if not ok then
return nil, M.join_space(create_err, error)
end
return dir
end
-- parser_dir exists, use it if it's read/write
if luv.fs_access(dir, "RW") then
return dir
end
-- parser_dir exists but isn't read/write, give up
return nil, M.join_space(writeable_err, dir, "'")
end
function M.get_package_path()
-- Path to this source file, removing the leading '@'
local source = string.sub(debug.getinfo(1, "S").source, 2)
-- Path to the package root
return fn.fnamemodify(source, ":p:h:h:h")
end
function M.get_cache_dir()
local cache_dir = fn.stdpath "data"
if luv.fs_access(cache_dir, "RW") then
return cache_dir
elseif luv.fs_access("/tmp", "RW") then
return "/tmp"
end
return nil, M.join_space("Invalid cache rights,", fn.stdpath "data", "or /tmp should be read/write")
end
-- Returns $XDG_DATA_HOME/nvim/site, but could use any directory that is in
-- runtimepath
function M.get_site_dir()
return M.join_path(fn.stdpath "data", "site")
end
-- Gets a property at path
---@param tbl table the table to access
---@param path string the '.' separated path
---@return table|nil result the value at path or nil
function M.get_at_path(tbl, path)
if path == "" then
return tbl
end
local segments = vim.split(path, ".", true)
---@type table[]|table
local result = tbl
for _, segment in ipairs(segments) do
if type(result) == "table" then
---@type table
-- TODO: figure out the actual type of tbl
result = result[segment]
end
end
return result
end
function M.set_jump()
vim.cmd "normal! m'"
end
-- Filters a list based on the given predicate
---@param tbl any[] The list to filter
---@param predicate fun(v:any, i:number):boolean The predicate to filter with
function M.filter(tbl, predicate)
local result = {}
for i, v in ipairs(tbl) do
if predicate(v, i) then
table.insert(result, v)
end
end
return result
end
-- Returns a list of all values from the first list
-- that are not present in the second list.
---@param tbl1 any[] The first table
---@param tbl2 any[] The second table
---@return table
function M.difference(tbl1, tbl2)
return M.filter(tbl1, function(v)
return not vim.tbl_contains(tbl2, v)
end)
end
function M.identity(a)
return a
end
-- Returns a function returning the given value
---@param a any
---@return fun():any
function M.constant(a)
return function()
return a
end
end
-- Returns a function that returns the given value if it is a function,
-- otherwise returns a function that returns the given value.
---@param a any
---@return fun(...):any
function M.to_func(a)
return type(a) == "function" and a or M.constant(a)
end
---@return string|nil
function M.ts_cli_version()
if fn.executable "tree-sitter" == 1 then
local handle = io.popen "tree-sitter -V"
if not handle then
return
end
local result = handle:read "*a"
handle:close()
return vim.split(result, "\n")[1]:match "[^tree%psitter ].*"
end
end
return M

View file

@ -1,2 +0,0 @@
*
!.gitignore

2
parser/.gitignore vendored
View file

@ -1,2 +0,0 @@
*
!.gitignore

69
plugin/filetypes.lua Normal file
View file

@ -0,0 +1,69 @@
local filetypes = {
angular = { 'htmlangular' },
bash = { 'sh' },
bibtex = { 'bib' },
c_sharp = { 'cs', 'csharp' },
commonlisp = { 'lisp' },
cooklang = { 'cook' },
devicetree = { 'dts' },
diff = { 'gitdiff' },
eex = { 'eelixir' },
elixir = { 'ex' },
embedded_template = { 'eruby' },
erlang = { 'erl' },
facility = { 'fsd' },
faust = { 'dsp' },
gdshader = { 'gdshaderinc' },
git_config = { 'gitconfig' },
git_rebase = { 'gitrebase' },
glimmer = { 'handlebars', 'html.handlebars' },
godot_resource = { 'gdresource' },
haskell = { 'hs' },
haskell_persistent = { 'haskellpersistent' },
idris = { 'idris2' },
ini = { 'confini', 'dosini' },
janet_simple = { 'janet' },
javascript = { 'javascriptreact', 'ecma', 'ecmascript', 'jsx', 'js' },
json = { 'jsonc' },
glimmer_javascript = { 'javascript.glimmer' },
latex = { 'tex' },
linkerscript = { 'ld' },
m68k = { 'asm68k' },
make = { 'automake' },
markdown = { 'pandoc' },
muttrc = { 'neomuttrc' },
ocaml_interface = { 'ocamlinterface' },
perl = { 'pl' },
poe_filter = { 'poefilter' },
powershell = { 'ps1' },
properties = { 'jproperties' },
python = { 'py', 'gyp' },
qmljs = { 'qml' },
runescript = { 'clientscript' },
scala = { 'sbt' },
slang = { 'shaderslang' },
sqp = { 'mysqp' },
ssh_config = { 'sshconfig' },
starlark = { 'bzl' },
surface = { 'sface' },
systemverilog = { 'verilog' },
t32 = { 'trace32' },
tcl = { 'expect' },
terraform = { 'terraform-vars' },
textproto = { 'pbtxt' },
tlaplus = { 'tla' },
tsx = { 'typescriptreact', 'typescript.tsx' },
typescript = { 'ts' },
glimmer_typescript = { 'typescript.glimmer' },
typst = { 'typ' },
udev = { 'udevrules' },
uxntal = { 'tal', 'uxn' },
v = { 'vlang' },
vhs = { 'tape' },
xml = { 'xsd', 'xslt', 'svg' },
xresources = { 'xdefaults' },
}
for lang, ft in pairs(filetypes) do
vim.treesitter.language.register(lang, ft)
end

View file

@ -1,34 +1,75 @@
-- Last Change: 2022 Apr 16
if vim.g.loaded_nvim_treesitter then
return
end
vim.g.loaded_nvim_treesitter = true
-- setup modules
require("nvim-treesitter").setup()
local api = vim.api
-- define autocommands
local augroup = api.nvim_create_augroup("NvimTreesitter", {})
local function complete_available_parsers(arglead)
return vim.tbl_filter(
--- @param v string
function(v)
return v:find(arglead) ~= nil
end,
require('nvim-treesitter.config').get_available()
)
end
api.nvim_create_autocmd("Filetype", {
pattern = "query",
group = augroup,
callback = function()
api.nvim_clear_autocmds {
group = augroup,
event = "BufWritePost",
}
api.nvim_create_autocmd("BufWritePost", {
group = augroup,
buffer = 0,
callback = function(opts)
require("nvim-treesitter.query").invalidate_query_file(opts.file)
end,
desc = "Invalidate query file",
})
end,
desc = "Reload query",
local function complete_installed_parsers(arglead)
return vim.tbl_filter(
--- @param v string
function(v)
return v:find(arglead) ~= nil
end,
require('nvim-treesitter.config').get_installed()
)
end
-- create user commands
api.nvim_create_user_command('TSInstall', function(args)
require('nvim-treesitter.install').install(args.fargs, { force = args.bang, summary = true })
end, {
nargs = '+',
bang = true,
bar = true,
complete = complete_available_parsers,
desc = 'Install treesitter parsers',
})
api.nvim_create_user_command('TSInstallFromGrammar', function(args)
require('nvim-treesitter.install').install(args.fargs, {
generate = true,
summary = true,
force = args.bang,
})
end, {
nargs = '+',
bang = true,
bar = true,
complete = complete_available_parsers,
desc = 'Install treesitter parsers from grammar',
})
api.nvim_create_user_command('TSUpdate', function(args)
require('nvim-treesitter.install').update(args.fargs, { summary = true })
end, {
nargs = '*',
bar = true,
complete = complete_installed_parsers,
desc = 'Update installed treesitter parsers',
})
api.nvim_create_user_command('TSUninstall', function(args)
require('nvim-treesitter.install').uninstall(args.fargs, { summary = true })
end, {
nargs = '+',
bar = true,
complete = complete_installed_parsers,
desc = 'Uninstall treesitter parsers',
})
api.nvim_create_user_command('TSLog', function()
require('nvim-treesitter.log').show()
end, {
desc = 'View log messages',
})

View file

@ -0,0 +1,41 @@
local query = vim.treesitter.query
local predicates = {
---@param match table<integer,TSNode[]>
---@param pred any[]
---@param any boolean
---@return boolean
['kind-eq'] = function(match, pred, any)
local nodes = match[pred[2]]
if not nodes or #nodes == 0 then
return true
end
local types = { unpack(pred, 3) }
for _, node in ipairs(nodes) do
local res = vim.list_contains(types, node:type())
if any and res then
return true
elseif not any and not res then
return false
end
end
return not any
end,
}
-- register custom predicates (overwrite existing; needed for CI)
---@param match table<integer,TSNode[]>
---@param pred any[]
---@return boolean
query.add_predicate('kind-eq?', function(match, _, _, pred)
return predicates['kind-eq'](match, pred, false)
end, { force = true })
---@param match table<integer,TSNode[]>
---@param pred any[]
---@return boolean
query.add_predicate('any-kind-eq?', function(match, _, _, pred)
return predicates['kind-eq'](match, pred, true)
end, { force = true })

View file

@ -1,5 +0,0 @@
((preproc_arg) @injection.content
(#set! injection.language "arduino"))
((comment) @injection.content
(#set! injection.language "comment"))

View file

@ -1,15 +0,0 @@
([
(directive)
(directive_start)
(directive_end)
] @tag
(#set! priority 101))
([
(bracket_start)
(bracket_end)
] @tag.delimiter
(#set! priority 101))
((comment) @comment @spell
(#set! priority 101))

View file

@ -1,3 +0,0 @@
(directive_start) @indent.begin
(directive_end) @indent.end

View file

@ -1,15 +0,0 @@
((text) @injection.content
(#set! injection.combined)
(#set! injection.language html))
((text) @injection.content
(#has-ancestor? @injection.content "envoy")
(#set! injection.combined)
(#set! injection.language bash))
((php_only) @injection.content
(#set! injection.combined)
(#set! injection.language php_only))
((parameter) @injection.content
(#set! injection.language php_only))

View file

@ -1,75 +0,0 @@
(object_id) @variable
(string) @string
(escape_sequence) @string.escape
(comment) @comment @spell
(constant) @constant.builtin
(boolean) @boolean
(using) @keyword.import
(template) @keyword
(decorator) @attribute
(property_definition
(property_name) @property)
(object) @type
(signal_binding
(signal_name) @function.builtin)
(signal_binding
(function
(identifier)) @function)
(signal_binding
"swapped" @keyword)
(styles_list
"styles" @function.macro)
(layout_definition
"layout" @function.macro)
(gettext_string
"_" @function.builtin)
(menu_definition
"menu" @keyword)
(menu_section
"section" @keyword)
(menu_item
"item" @function.macro)
(import_statement
(gobject_library) @module)
(import_statement
(version_number) @number.float)
(float) @number.float
(number) @number
[
";"
"."
","
] @punctuation.delimiter
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket

View file

@ -1,13 +0,0 @@
((preproc_arg) @injection.content
(#set! injection.language "cpp"))
((comment) @injection.content
(#set! injection.language "comment"))
((comment) @injection.content
(#lua-match? @injection.content "/[*\/][!*\/]<?[^a-zA-Z]")
(#set! injection.language "doxygen"))
(raw_string_literal
delimiter: (raw_string_delimiter) @injection.language
(raw_string_content) @injection.content)

View file

@ -1,5 +0,0 @@
((preproc_arg) @injection.content
(#set! injection.language "cuda"))
((comment) @injection.content
(#set! injection.language "comment"))

View file

@ -1,55 +0,0 @@
(comment) @comment @spell
(section
(section_name) @string.special.path)
(character_choice
(character) @constant)
(character_range
start: (character) @constant
end: (character) @constant)
[
"["
"]"
"{"
"}"
] @punctuation.bracket
[
","
".."
(path_separator)
] @punctuation.delimiter
[
"-"
"="
(negation)
] @operator
[
(wildcard_characters)
(wildcard_any_characters)
(wildcard_single_character)
] @character.special
(escaped_character) @string.escape
(pair
key: (identifier) @property
value: (_) @string)
(boolean) @boolean
(integer) @number
(unset) @constant.builtin
[
(spelling_language)
(indent_style)
(end_of_line)
(charset)
] @string.special

View file

@ -1,6 +0,0 @@
[
(comment)
(block)
(afx_comment)
(afx_element)
] @fold

View file

@ -1,132 +0,0 @@
(comment) @comment @spell
(afx_comment) @comment @spell
; identifiers afx
(afx_opening_element
(afx_identifier) @tag)
(afx_closing_element
(afx_identifier) @tag)
(afx_element_self_closing
(afx_identifier) @tag)
(afx_attribute
(afx_property_identifier) @tag.attribute)
(afx_text) @spell
; identifiers eel
(eel_object_path
(eel_path_identifier) @variable.builtin
(#any-of? @variable.builtin "this" "props"))
(eel_object_path
(eel_path_identifier) @variable)
(eel_object_pair
key: (eel_property_name) @property)
(eel_method_name) @function
(eel_parameter) @variable
; identifiers fusion
; -----------
(path_part) @property
(meta_property) @attribute
(prototype_signature
"prototype" @keyword)
(include_statement
"include" @keyword.import
(source_file) @string.special.url)
(namespace_declaration
"namespace" @keyword.type
(alias_namespace) @module)
(type
name: (type_name) @type)
; tokens
; ------
(afx_opening_element
[
"<"
">"
] @punctuation.bracket)
(afx_closing_element
[
"<"
">"
"/"
] @punctuation.bracket)
(afx_element_self_closing
[
"<"
"/>"
] @punctuation.bracket)
[
(package_name)
(alias_namespace)
] @module
(namespace_declaration
"=" @operator)
(assignment
"=" @operator)
(copy
"<" @operator)
(deletion) @operator
(eel_binary_expression
operator: _ @operator)
(eel_not_expression
[
"!"
"not"
] @operator)
(string) @string
(number) @number
(boolean) @boolean
(null) @constant.builtin
(value_expression
start: _ @punctuation.special
end: _ @punctuation.special)
[
"("
")"
"{"
"}"
"["
"]"
] @punctuation.bracket
[
":"
"."
"?"
] @punctuation.delimiter
(eel_ternary_expression
[
"?"
":"
] @keyword.conditional.ternary)

View file

@ -1,24 +0,0 @@
[
(block)
(value_dsl)
(afx_element)
(afx_element_self_closing)
(eel_array)
(eel_object)
] @indent.begin
(block
end: _ @indent.branch)
(value_dsl
end: _ @indent.branch)
(eel_array
end: _ @indent.branch)
(eel_object
end: _ @indent.branch)
(afx_closing_element) @indent.branch
(comment) @indent.ignore

View file

@ -1,5 +0,0 @@
([
(comment)
(afx_comment)
] @injection.content
(#set! injection.language "comment"))

View file

@ -1,23 +0,0 @@
; Fusion base
(block) @local.scope
(namespace_declaration
(alias_namespace) @local.definition.namespace)
(property
(path
(path_part) @local.definition.field))
(type
namespace: (package_name)? @local.definition.namespace
name: (type_name) @local.definition.type)
; Eel Expressions
(eel_arrow_function) @local.scope
(eel_object) @local.scope
(eel_parameter) @local.definition.parameter
(eel_object_pair
key: (eel_property_name) @local.definition.field)

View file

@ -1,422 +0,0 @@
; Basic
(identifier) @variable
(name) @variable
(type
(identifier) @type)
(comment) @comment @spell
(string_name) @string
(string) @string
(float) @number.float
(integer) @number
(null) @constant
(setter) @function
(getter) @function
(set_body
"set" @keyword.function)
(get_body
"get" @keyword.function)
(static_keyword) @keyword.modifier
(tool_statement) @keyword
(breakpoint_statement) @keyword.debug
(inferred_type) @operator
[
(true)
(false)
] @boolean
[
(get_node)
(node_path)
] @string.special.url
(class_name_statement
(name) @type) @keyword
(const_statement
"const" @keyword.modifier
(name) @constant)
(expression_statement
(string) @comment @spell)
; Functions
(constructor_definition
"_init" @constructor)
(function_definition
(name) @function)
(parameters
(identifier) @variable.parameter)
(typed_parameter
(identifier) @variable.parameter)
(default_parameter
(identifier) @variable.parameter)
(typed_default_parameter
(identifier) @variable.parameter)
(call
(identifier) @function.call)
(call
(identifier) @keyword.import
(#any-of? @keyword.import "preload" "load"))
; Properties and Methods
; We'll use @property since that's the term Godot uses.
; But, should (source (variable_statement (name))) be @property, too? Since a
; script file is a class in gdscript.
(class_definition
(body
(variable_statement
(name) @property)))
; Same question but for methods?
(class_definition
(body
(function_definition
(name) @function.method)))
(attribute_call
(identifier) @function.method.call)
(attribute_subscript
(identifier) @property)
(attribute
(_)
(identifier) @property)
; Identifier naming conventions
; - Make sure the following query is below the attribute queries so that it
; takes precedence on a `(type (attribute (identifier)))`
((identifier) @type
(#lua-match? @type "^[A-Z]"))
((identifier) @constant
(#lua-match? @constant "^[A-Z][A-Z_0-9]*$"))
; Enums
(enumerator
left: (identifier) @constant)
; Special Builtins
((identifier) @variable.builtin
(#any-of? @variable.builtin "self" "super"))
(attribute_call
(identifier) @keyword.operator
(#eq? @keyword.operator "new"))
; Match Pattern
[
(underscore)
(pattern_open_ending)
] @character.special
; Alternations
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
[
","
"."
":"
] @punctuation.delimiter
[
"if"
"elif"
"else"
"match"
] @keyword.conditional
(pattern_guard
"when" @keyword.conditional)
[
"for"
"while"
"break"
"continue"
] @keyword.repeat
[
"~"
"-"
"*"
"/"
"%"
"+"
"-"
"<<"
">>"
"&"
"^"
"|"
"<"
">"
"=="
"!="
">="
"<="
"!"
"&&"
"||"
"="
"+="
"-="
"*="
"/="
"%="
"&="
"|="
"->"
] @operator
[
"and"
"as"
"in"
"is"
"not"
"or"
] @keyword.operator
[
"pass"
"class_name"
"extends"
"signal"
"var"
"onready"
"setget"
"remote"
"master"
"puppet"
"remotesync"
"mastersync"
"puppetsync"
] @keyword
"export" @keyword.import
[
"enum"
"class"
] @keyword.type
"func" @keyword.function
"return" @keyword.return
"await" @keyword.coroutine
(call
(identifier) @keyword.coroutine
(#eq? @keyword.coroutine "yield"))
; Builtins
; generated from
; - godot commit: fb10e67fef
; - https://github.com/godotengine/godot/blob/fb10e67fef/doc/classes
; - https://github.com/godotengine/godot/blob/fb10e67fef/doc/classes/@GlobalScope.xml
; - https://github.com/godotengine/godot/blob/fb10e67fef/modules/gdscript/doc_classes/@GDScript.xml
; Built-in Annotations
((annotation
"@" @attribute
(identifier) @attribute)
(#any-of? @attribute
; from modules/gdscript/doc_classes/@GDScript.xml
"export" "export_category" "export_color_no_alpha" "export_custom" "export_dir" "export_enum"
"export_exp_easing" "export_file" "export_flags" "export_flags_2d_navigation"
"export_flags_2d_physics" "export_flags_2d_render" "export_flags_3d_navigation"
"export_flags_3d_physics" "export_flags_3d_render" "export_flags_avoidance" "export_global_dir"
"export_global_file" "export_group" "export_multiline" "export_node_path" "export_placeholder"
"export_range" "export_storage" "export_subgroup" "icon" "onready" "rpc" "static_unload" "tool"
"warning_ignore"))
; Builtin Types
((identifier) @type.builtin
(#any-of? @type.builtin
; from doc/classes/*.xml
"AABB" "Array" "Basis" "Callable" "Color" "Dictionary" "NodePath" "PackedByteArray"
"PackedColorArray" "PackedFloat32Array" "PackedFloat64Array" "PackedInt32Array"
"PackedInt64Array" "PackedStringArray" "PackedVector2Array" "PackedVector3Array" "Plane"
"Projection" "Quaternion" "RID" "Rect2" "Rect2i" "Signal" "String" "StringName" "Transform2D"
"Transform3D" "Vector2" "Vector2i" "Vector3" "Vector3i" "Vector4" "Vector4i" "bool" "float"
"int"
; from doc/classes/@GlobalScope.xml
"AudioServer" "CameraServer" "ClassDB" "DisplayServer" "EditorInterface" "Engine"
"EngineDebugger" "GDExtensionManager" "Geometry2D" "Geometry3D" "GodotSharp" "IP" "Input"
"InputMap" "JavaClassWrapper" "JavaScriptBridge" "Marshalls" "NavigationMeshGenerator"
"NavigationServer2D" "NavigationServer3D" "OS" "Performance" "PhysicsServer2D"
"PhysicsServer2DManager" "PhysicsServer3D" "PhysicsServer3DManager" "ProjectSettings"
"RenderingServer" "ResourceLoader" "ResourceSaver" "ResourceUID" "TextServerManager" "ThemeDB"
"Time" "TranslationServer" "WorkerThreadPool" "XRServer"))
; Builtin Funcs
(call
(identifier) @function.builtin
(#any-of? @function.builtin
; from doc/classes/@GlobalScope.xml
"abs" "absf" "absi" "acos" "acosh" "angle_difference" "asin" "asinh" "atan" "atan2" "atanh"
"bezier_derivative" "bezier_interpolate" "bytes_to_var" "bytes_to_var_with_objects" "ceil"
"ceilf" "ceili" "clamp" "clampf" "clampi" "cos" "cosh" "cubic_interpolate"
"cubic_interpolate_angle" "cubic_interpolate_angle_in_time" "cubic_interpolate_in_time"
"db_to_linear" "deg_to_rad" "ease" "error_string" "exp" "floor" "floorf" "floori" "fmod"
"fposmod" "hash" "instance_from_id" "inverse_lerp" "is_equal_approx" "is_finite" "is_inf"
"is_instance_id_valid" "is_instance_valid" "is_nan" "is_same" "is_zero_approx" "lerp"
"lerp_angle" "lerpf" "linear_to_db" "log" "max" "maxf" "maxi" "min" "minf" "mini" "move_toward"
"nearest_po2" "pingpong" "posmod" "pow" "print" "print_rich" "print_verbose" "printerr"
"printraw" "prints" "printt" "push_error" "push_warning" "rad_to_deg" "rand_from_seed" "randf"
"randf_range" "randfn" "randi" "randi_range" "randomize" "remap" "rid_allocate_id"
"rid_from_int64" "rotate_toward" "round" "roundf" "roundi" "seed" "sign" "signf" "signi" "sin"
"sinh" "smoothstep" "snapped" "snappedf" "snappedi" "sqrt" "step_decimals" "str" "str_to_var"
"tan" "tanh" "type_convert" "type_string" "typeof" "var_to_bytes" "var_to_bytes_with_objects"
"var_to_str" "weakref" "wrap" "wrapf" "wrapi"
; from modules/gdscript/doc_classes/@GDScript.xml
"Color8" "assert" "char" "convert" "dict_to_inst" "get_stack" "inst_to_dict" "is_instance_of"
"len" "load" "preload" "print_debug" "print_stack" "range" "type_exists"))
; Builtin Constants
((identifier) @constant.builtin
(#any-of? @constant.builtin
; from modules/gdscript/doc_classes/@GDScript.xml
"INF" "NAN" "PI" "TAU"
; from doc/classes/@GlobalScope.xml
"CLOCKWISE" "CORNER_BOTTOM_LEFT" "CORNER_BOTTOM_RIGHT" "CORNER_TOP_LEFT" "CORNER_TOP_RIGHT"
"COUNTERCLOCKWISE" "ERR_ALREADY_EXISTS" "ERR_ALREADY_IN_USE" "ERR_BUG" "ERR_BUSY"
"ERR_CANT_ACQUIRE_RESOURCE" "ERR_CANT_CONNECT" "ERR_CANT_CREATE" "ERR_CANT_FORK" "ERR_CANT_OPEN"
"ERR_CANT_RESOLVE" "ERR_COMPILATION_FAILED" "ERR_CONNECTION_ERROR" "ERR_CYCLIC_LINK"
"ERR_DATABASE_CANT_READ" "ERR_DATABASE_CANT_WRITE" "ERR_DOES_NOT_EXIST" "ERR_DUPLICATE_SYMBOL"
"ERR_FILE_ALREADY_IN_USE" "ERR_FILE_BAD_DRIVE" "ERR_FILE_BAD_PATH" "ERR_FILE_CANT_OPEN"
"ERR_FILE_CANT_READ" "ERR_FILE_CANT_WRITE" "ERR_FILE_CORRUPT" "ERR_FILE_EOF"
"ERR_FILE_MISSING_DEPENDENCIES" "ERR_FILE_NOT_FOUND" "ERR_FILE_NO_PERMISSION"
"ERR_FILE_UNRECOGNIZED" "ERR_HELP" "ERR_INVALID_DATA" "ERR_INVALID_DECLARATION"
"ERR_INVALID_PARAMETER" "ERR_LINK_FAILED" "ERR_LOCKED" "ERR_METHOD_NOT_FOUND"
"ERR_OUT_OF_MEMORY" "ERR_PARAMETER_RANGE_ERROR" "ERR_PARSE_ERROR" "ERR_PRINTER_ON_FIRE"
"ERR_QUERY_FAILED" "ERR_SCRIPT_FAILED" "ERR_SKIP" "ERR_TIMEOUT" "ERR_UNAUTHORIZED"
"ERR_UNAVAILABLE" "ERR_UNCONFIGURED" "EULER_ORDER_XYZ" "EULER_ORDER_XZY" "EULER_ORDER_YXZ"
"EULER_ORDER_YZX" "EULER_ORDER_ZXY" "EULER_ORDER_ZYX" "FAILED" "HORIZONTAL"
"HORIZONTAL_ALIGNMENT_CENTER" "HORIZONTAL_ALIGNMENT_FILL" "HORIZONTAL_ALIGNMENT_LEFT"
"HORIZONTAL_ALIGNMENT_RIGHT" "INLINE_ALIGNMENT_BASELINE_TO" "INLINE_ALIGNMENT_BOTTOM"
"INLINE_ALIGNMENT_BOTTOM_TO" "INLINE_ALIGNMENT_CENTER" "INLINE_ALIGNMENT_CENTER_TO"
"INLINE_ALIGNMENT_IMAGE_MASK" "INLINE_ALIGNMENT_TEXT_MASK" "INLINE_ALIGNMENT_TOP"
"INLINE_ALIGNMENT_TOP_TO" "INLINE_ALIGNMENT_TO_BASELINE" "INLINE_ALIGNMENT_TO_BOTTOM"
"INLINE_ALIGNMENT_TO_CENTER" "INLINE_ALIGNMENT_TO_TOP" "JOY_AXIS_INVALID" "JOY_AXIS_LEFT_X"
"JOY_AXIS_LEFT_Y" "JOY_AXIS_MAX" "JOY_AXIS_RIGHT_X" "JOY_AXIS_RIGHT_Y" "JOY_AXIS_SDL_MAX"
"JOY_AXIS_TRIGGER_LEFT" "JOY_AXIS_TRIGGER_RIGHT" "JOY_BUTTON_A" "JOY_BUTTON_B" "JOY_BUTTON_BACK"
"JOY_BUTTON_DPAD_DOWN" "JOY_BUTTON_DPAD_LEFT" "JOY_BUTTON_DPAD_RIGHT" "JOY_BUTTON_DPAD_UP"
"JOY_BUTTON_GUIDE" "JOY_BUTTON_INVALID" "JOY_BUTTON_LEFT_SHOULDER" "JOY_BUTTON_LEFT_STICK"
"JOY_BUTTON_MAX" "JOY_BUTTON_MISC1" "JOY_BUTTON_PADDLE1" "JOY_BUTTON_PADDLE2"
"JOY_BUTTON_PADDLE3" "JOY_BUTTON_PADDLE4" "JOY_BUTTON_RIGHT_SHOULDER" "JOY_BUTTON_RIGHT_STICK"
"JOY_BUTTON_SDL_MAX" "JOY_BUTTON_START" "JOY_BUTTON_TOUCHPAD" "JOY_BUTTON_X" "JOY_BUTTON_Y"
"KEY_0" "KEY_1" "KEY_2" "KEY_3" "KEY_4" "KEY_5" "KEY_6" "KEY_7" "KEY_8" "KEY_9" "KEY_A"
"KEY_ALT" "KEY_AMPERSAND" "KEY_APOSTROPHE" "KEY_ASCIICIRCUM" "KEY_ASCIITILDE" "KEY_ASTERISK"
"KEY_AT" "KEY_B" "KEY_BACK" "KEY_BACKSLASH" "KEY_BACKSPACE" "KEY_BACKTAB" "KEY_BAR"
"KEY_BRACELEFT" "KEY_BRACERIGHT" "KEY_BRACKETLEFT" "KEY_BRACKETRIGHT" "KEY_C" "KEY_CAPSLOCK"
"KEY_CLEAR" "KEY_CODE_MASK" "KEY_COLON" "KEY_COMMA" "KEY_CTRL" "KEY_D" "KEY_DELETE" "KEY_DOLLAR"
"KEY_DOWN" "KEY_E" "KEY_END" "KEY_ENTER" "KEY_EQUAL" "KEY_ESCAPE" "KEY_EXCLAM" "KEY_F" "KEY_F1"
"KEY_F10" "KEY_F11" "KEY_F12" "KEY_F13" "KEY_F14" "KEY_F15" "KEY_F16" "KEY_F17" "KEY_F18"
"KEY_F19" "KEY_F2" "KEY_F20" "KEY_F21" "KEY_F22" "KEY_F23" "KEY_F24" "KEY_F25" "KEY_F26"
"KEY_F27" "KEY_F28" "KEY_F29" "KEY_F3" "KEY_F30" "KEY_F31" "KEY_F32" "KEY_F33" "KEY_F34"
"KEY_F35" "KEY_F4" "KEY_F5" "KEY_F6" "KEY_F7" "KEY_F8" "KEY_F9" "KEY_FAVORITES" "KEY_FORWARD"
"KEY_G" "KEY_GLOBE" "KEY_GREATER" "KEY_H" "KEY_HELP" "KEY_HOME" "KEY_HOMEPAGE" "KEY_HYPER"
"KEY_I" "KEY_INSERT" "KEY_J" "KEY_JIS_EISU" "KEY_JIS_KANA" "KEY_K" "KEY_KEYBOARD" "KEY_KP_0"
"KEY_KP_1" "KEY_KP_2" "KEY_KP_3" "KEY_KP_4" "KEY_KP_5" "KEY_KP_6" "KEY_KP_7" "KEY_KP_8"
"KEY_KP_9" "KEY_KP_ADD" "KEY_KP_DIVIDE" "KEY_KP_ENTER" "KEY_KP_MULTIPLY" "KEY_KP_PERIOD"
"KEY_KP_SUBTRACT" "KEY_L" "KEY_LAUNCH0" "KEY_LAUNCH1" "KEY_LAUNCH2" "KEY_LAUNCH3" "KEY_LAUNCH4"
"KEY_LAUNCH5" "KEY_LAUNCH6" "KEY_LAUNCH7" "KEY_LAUNCH8" "KEY_LAUNCH9" "KEY_LAUNCHA"
"KEY_LAUNCHB" "KEY_LAUNCHC" "KEY_LAUNCHD" "KEY_LAUNCHE" "KEY_LAUNCHF" "KEY_LAUNCHMAIL"
"KEY_LAUNCHMEDIA" "KEY_LEFT" "KEY_LESS" "KEY_LOCATION_LEFT" "KEY_LOCATION_RIGHT"
"KEY_LOCATION_UNSPECIFIED" "KEY_M" "KEY_MASK_ALT" "KEY_MASK_CMD_OR_CTRL" "KEY_MASK_CTRL"
"KEY_MASK_GROUP_SWITCH" "KEY_MASK_KPAD" "KEY_MASK_META" "KEY_MASK_SHIFT" "KEY_MEDIANEXT"
"KEY_MEDIAPLAY" "KEY_MEDIAPREVIOUS" "KEY_MEDIARECORD" "KEY_MEDIASTOP" "KEY_MENU" "KEY_META"
"KEY_MINUS" "KEY_MODIFIER_MASK" "KEY_N" "KEY_NONE" "KEY_NUMBERSIGN" "KEY_NUMLOCK" "KEY_O"
"KEY_OPENURL" "KEY_P" "KEY_PAGEDOWN" "KEY_PAGEUP" "KEY_PARENLEFT" "KEY_PARENRIGHT" "KEY_PAUSE"
"KEY_PERCENT" "KEY_PERIOD" "KEY_PLUS" "KEY_PRINT" "KEY_Q" "KEY_QUESTION" "KEY_QUOTEDBL"
"KEY_QUOTELEFT" "KEY_R" "KEY_REFRESH" "KEY_RIGHT" "KEY_S" "KEY_SCROLLLOCK" "KEY_SEARCH"
"KEY_SECTION" "KEY_SEMICOLON" "KEY_SHIFT" "KEY_SLASH" "KEY_SPACE" "KEY_SPECIAL" "KEY_STANDBY"
"KEY_STOP" "KEY_SYSREQ" "KEY_T" "KEY_TAB" "KEY_U" "KEY_UNDERSCORE" "KEY_UNKNOWN" "KEY_UP"
"KEY_V" "KEY_VOLUMEDOWN" "KEY_VOLUMEMUTE" "KEY_VOLUMEUP" "KEY_W" "KEY_X" "KEY_Y" "KEY_YEN"
"KEY_Z" "METHOD_FLAGS_DEFAULT" "METHOD_FLAG_CONST" "METHOD_FLAG_EDITOR" "METHOD_FLAG_NORMAL"
"METHOD_FLAG_OBJECT_CORE" "METHOD_FLAG_STATIC" "METHOD_FLAG_VARARG" "METHOD_FLAG_VIRTUAL"
"MIDI_MESSAGE_ACTIVE_SENSING" "MIDI_MESSAGE_AFTERTOUCH" "MIDI_MESSAGE_CHANNEL_PRESSURE"
"MIDI_MESSAGE_CONTINUE" "MIDI_MESSAGE_CONTROL_CHANGE" "MIDI_MESSAGE_NONE"
"MIDI_MESSAGE_NOTE_OFF" "MIDI_MESSAGE_NOTE_ON" "MIDI_MESSAGE_PITCH_BEND"
"MIDI_MESSAGE_PROGRAM_CHANGE" "MIDI_MESSAGE_QUARTER_FRAME" "MIDI_MESSAGE_SONG_POSITION_POINTER"
"MIDI_MESSAGE_SONG_SELECT" "MIDI_MESSAGE_START" "MIDI_MESSAGE_STOP"
"MIDI_MESSAGE_SYSTEM_EXCLUSIVE" "MIDI_MESSAGE_SYSTEM_RESET" "MIDI_MESSAGE_TIMING_CLOCK"
"MIDI_MESSAGE_TUNE_REQUEST" "MOUSE_BUTTON_LEFT" "MOUSE_BUTTON_MASK_LEFT"
"MOUSE_BUTTON_MASK_MB_XBUTTON1" "MOUSE_BUTTON_MASK_MB_XBUTTON2" "MOUSE_BUTTON_MASK_MIDDLE"
"MOUSE_BUTTON_MASK_RIGHT" "MOUSE_BUTTON_MIDDLE" "MOUSE_BUTTON_NONE" "MOUSE_BUTTON_RIGHT"
"MOUSE_BUTTON_WHEEL_DOWN" "MOUSE_BUTTON_WHEEL_LEFT" "MOUSE_BUTTON_WHEEL_RIGHT"
"MOUSE_BUTTON_WHEEL_UP" "MOUSE_BUTTON_XBUTTON1" "MOUSE_BUTTON_XBUTTON2" "OK" "OP_ADD" "OP_AND"
"OP_BIT_AND" "OP_BIT_NEGATE" "OP_BIT_OR" "OP_BIT_XOR" "OP_DIVIDE" "OP_EQUAL" "OP_GREATER"
"OP_GREATER_EQUAL" "OP_IN" "OP_LESS" "OP_LESS_EQUAL" "OP_MAX" "OP_MODULE" "OP_MULTIPLY"
"OP_NEGATE" "OP_NOT" "OP_NOT_EQUAL" "OP_OR" "OP_POSITIVE" "OP_POWER" "OP_SHIFT_LEFT"
"OP_SHIFT_RIGHT" "OP_SUBTRACT" "OP_XOR" "PROPERTY_HINT_ARRAY_TYPE"
"PROPERTY_HINT_COLOR_NO_ALPHA" "PROPERTY_HINT_DIR" "PROPERTY_HINT_ENUM"
"PROPERTY_HINT_ENUM_SUGGESTION" "PROPERTY_HINT_EXPRESSION" "PROPERTY_HINT_EXP_EASING"
"PROPERTY_HINT_FILE" "PROPERTY_HINT_FLAGS" "PROPERTY_HINT_GLOBAL_DIR"
"PROPERTY_HINT_GLOBAL_FILE" "PROPERTY_HINT_GLOBAL_SAVE_FILE"
"PROPERTY_HINT_HIDE_QUATERNION_EDIT" "PROPERTY_HINT_INT_IS_OBJECTID"
"PROPERTY_HINT_INT_IS_POINTER" "PROPERTY_HINT_LAYERS_2D_NAVIGATION"
"PROPERTY_HINT_LAYERS_2D_PHYSICS" "PROPERTY_HINT_LAYERS_2D_RENDER"
"PROPERTY_HINT_LAYERS_3D_NAVIGATION" "PROPERTY_HINT_LAYERS_3D_PHYSICS"
"PROPERTY_HINT_LAYERS_3D_RENDER" "PROPERTY_HINT_LAYERS_AVOIDANCE" "PROPERTY_HINT_LINK"
"PROPERTY_HINT_LOCALE_ID" "PROPERTY_HINT_LOCALIZABLE_STRING" "PROPERTY_HINT_MAX"
"PROPERTY_HINT_MULTILINE_TEXT" "PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE"
"PROPERTY_HINT_NODE_PATH_VALID_TYPES" "PROPERTY_HINT_NODE_TYPE" "PROPERTY_HINT_NONE"
"PROPERTY_HINT_OBJECT_ID" "PROPERTY_HINT_OBJECT_TOO_BIG" "PROPERTY_HINT_PASSWORD"
"PROPERTY_HINT_PLACEHOLDER_TEXT" "PROPERTY_HINT_RANGE" "PROPERTY_HINT_RESOURCE_TYPE"
"PROPERTY_HINT_SAVE_FILE" "PROPERTY_HINT_TYPE_STRING" "PROPERTY_USAGE_ALWAYS_DUPLICATE"
"PROPERTY_USAGE_ARRAY" "PROPERTY_USAGE_CATEGORY" "PROPERTY_USAGE_CHECKABLE"
"PROPERTY_USAGE_CHECKED" "PROPERTY_USAGE_CLASS_IS_BITFIELD" "PROPERTY_USAGE_CLASS_IS_ENUM"
"PROPERTY_USAGE_DEFAULT" "PROPERTY_USAGE_DEFERRED_SET_RESOURCE" "PROPERTY_USAGE_EDITOR"
"PROPERTY_USAGE_EDITOR_BASIC_SETTING" "PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT"
"PROPERTY_USAGE_GROUP" "PROPERTY_USAGE_HIGH_END_GFX" "PROPERTY_USAGE_INTERNAL"
"PROPERTY_USAGE_KEYING_INCREMENTS" "PROPERTY_USAGE_NEVER_DUPLICATE"
"PROPERTY_USAGE_NIL_IS_VARIANT" "PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT" "PROPERTY_USAGE_NONE"
"PROPERTY_USAGE_NO_EDITOR" "PROPERTY_USAGE_NO_INSTANCE_STATE" "PROPERTY_USAGE_READ_ONLY"
"PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT" "PROPERTY_USAGE_RESTART_IF_CHANGED"
"PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE" "PROPERTY_USAGE_SCRIPT_VARIABLE" "PROPERTY_USAGE_SECRET"
"PROPERTY_USAGE_STORAGE" "PROPERTY_USAGE_STORE_IF_NULL" "PROPERTY_USAGE_SUBGROUP"
"PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED" "SIDE_BOTTOM" "SIDE_LEFT" "SIDE_RIGHT" "SIDE_TOP"
"TYPE_AABB" "TYPE_ARRAY" "TYPE_BASIS" "TYPE_BOOL" "TYPE_CALLABLE" "TYPE_COLOR" "TYPE_DICTIONARY"
"TYPE_FLOAT" "TYPE_INT" "TYPE_MAX" "TYPE_NIL" "TYPE_NODE_PATH" "TYPE_OBJECT"
"TYPE_PACKED_BYTE_ARRAY" "TYPE_PACKED_COLOR_ARRAY" "TYPE_PACKED_FLOAT32_ARRAY"
"TYPE_PACKED_FLOAT64_ARRAY" "TYPE_PACKED_INT32_ARRAY" "TYPE_PACKED_INT64_ARRAY"
"TYPE_PACKED_STRING_ARRAY" "TYPE_PACKED_VECTOR2_ARRAY" "TYPE_PACKED_VECTOR3_ARRAY" "TYPE_PLANE"
"TYPE_PROJECTION" "TYPE_QUATERNION" "TYPE_RECT2" "TYPE_RECT2I" "TYPE_RID" "TYPE_SIGNAL"
"TYPE_STRING" "TYPE_STRING_NAME" "TYPE_TRANSFORM2D" "TYPE_TRANSFORM3D" "TYPE_VECTOR2"
"TYPE_VECTOR2I" "TYPE_VECTOR3" "TYPE_VECTOR3I" "TYPE_VECTOR4" "TYPE_VECTOR4I" "VERTICAL"
"VERTICAL_ALIGNMENT_BOTTOM" "VERTICAL_ALIGNMENT_CENTER" "VERTICAL_ALIGNMENT_FILL"
"VERTICAL_ALIGNMENT_TOP"))

View file

@ -1,142 +0,0 @@
[
"render_mode"
"shader_type"
"group_uniforms"
"global"
"instance"
"const"
"varying"
"uniform"
] @keyword
"struct" @keyword.type
[
(precision_qualifier)
(interpolation_qualifier)
] @keyword.modifier
[
"in"
"out"
"inout"
] @keyword.modifier
[
"while"
"for"
] @keyword.repeat
[
"continue"
"break"
"return"
] @keyword.return
[
"if"
"else"
"switch"
"case"
"default"
] @keyword.conditional
[
"#"
"include"
] @keyword.directive
(string) @string
[
"="
"+="
"-="
"!"
"~"
"+"
"-"
"*"
"/"
"%"
"||"
"&&"
"|"
"^"
"&"
"=="
"!="
">"
">="
"<="
"<"
"<<"
">>"
"++"
"--"
] @operator
(boolean) @boolean
(integer) @number
(float) @number.float
[
"."
","
";"
] @punctuation.delimiter
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
(builtin_type) @type.builtin
(ident_type) @type.definition
[
(shader_type)
(render_mode)
(hint_name)
] @attribute
(builtin_variable) @constant.builtin
(builtin_function) @function.builtin
(group_uniforms_declaration
group_name: (ident) @property
subgroup_name: (ident) @property)
(struct_declaration
name: (ident) @type)
(struct_member
name: (ident) @property)
(function_declaration
name: (ident) @function)
(parameter
name: (ident) @variable.parameter)
(member_expr
member: (ident) @property)
(call_expr
function: [
(ident)
(builtin_type)
] @function)
(call_expr
function: (builtin_type) @function.call)
(comment) @comment @spell

View file

@ -1,21 +0,0 @@
; comments
((comment_statement) @injection.content
(#set! injection.language "comment"))
; <style> tags
((element_node
(element_node_start
(tag_name) @_tag_name
(#eq? @_tag_name "style"))) @injection.content
(#offset! @injection.content 0 7 0 -8)
(#set! injection.language "css")
(#set! injection.include-children))
; <script> tags
((element_node
(element_node_start
(tag_name) @_tag_name
(#eq? @_tag_name "script"))) @injection.content
(#offset! @injection.content 0 8 0 -9)
(#set! injection.language "glimmer_javascript")
(#set! injection.include-children))

View file

@ -1,5 +0,0 @@
((preproc_arg) @injection.content
(#set! injection.language "glsl"))
((comment) @injection.content
(#set! injection.language "comment"))

View file

@ -1,5 +0,0 @@
((preproc_arg) @injection.content
(#set! injection.language "hlsl"))
((comment) @injection.content
(#set! injection.language "comment"))

View file

@ -1,13 +0,0 @@
[
(source_file)
(dependency_list)
(module_list)
(dependency_declaration)
(module_declaration)
(module_declaration)
(package_declaration)
(main_declaration)
(executable_declaration)
(version_declaration)
(langversion_declaration)
] @fold

View file

@ -1,56 +0,0 @@
; Keywords
"package" @keyword.import
[
"authors"
"maintainers"
"license"
"brief"
"readme"
"homepage"
"sourceloc"
"bugtracker"
"opts"
"sourcedir"
"builddir"
"outputdir"
"prebuild"
"postbuild"
"preinstall"
"postinstall"
"preclean"
"postclean"
"version"
"langversion"
"modules"
"main"
"executable"
"depends"
] @keyword
[
"="
(version_range_op)
] @operator
"," @punctuation.delimiter
; Field values
(string_value) @string
(boolean_value) @boolean
; Version numbers and ranges
(version_number) @string.special
[
(dependency_item)
(package_name)
(module_name)
] @module
; Comments
[
(line_comment)
(block_comment)
] @comment @spell

View file

@ -1,33 +0,0 @@
; Indentation rules for Idris .ipkg files
[
(package_declaration)
(field_declaration)
(main_declaration)
(executable_declaration)
(version_declaration)
(langversion_declaration)
] @indent.begin
(dependency_declaration
"=" @indent.begin
(dependency_list
"," @indent.begin))
(module_declaration
"=" @indent.begin
(module_list
"," @indent.begin))
(field_declaration
"=" @indent.begin)
"=" @indent.branch
(string_value) @indent.begin
[
(line_comment)
(block_comment)
] @indent.ignore
(ERROR) @indent.auto

View file

@ -1,24 +0,0 @@
; Scopes
(source_file) @local.scope
; Definitions
(package_declaration
(package_name) @local.definition.import)
(module_declaration
(module_list
(module_name) @local.definition.namespace))
(main_declaration
(module_name) @local.definition.import)
(executable_declaration
(package_name) @local.definition.import)
; References
(dependency_declaration
(dependency_list
(dependency_item
(package_name) @local.reference)))
(module_name) @local.reference

View file

@ -1 +0,0 @@
; inherits: json

View file

@ -1,3 +0,0 @@
; inherits: json
(comment) @comment @spell

View file

@ -1,3 +0,0 @@
; inherits: json
(comment) @indent.ignore

View file

@ -1 +0,0 @@
; inherits: json

View file

@ -1,2 +0,0 @@
((comment)
(#set! injection.language "comment"))

View file

@ -1,74 +0,0 @@
(comment) @comment @spell
[
"forall"
"in"
"let"
"default"
"doc"
"rec"
] @keyword
"fun" @keyword.function
"import" @keyword.import
[
"if"
"then"
"else"
] @keyword.conditional
"match" @keyword.conditional
(types) @type
"Array" @type.builtin
; BUILTIN Constants
(bool) @boolean
"null" @constant.builtin
(num_literal) @number
(infix_op) @operator
(type_atom) @type
(enum_tag) @variable
(chunk_literal_single) @string
(chunk_literal_multi) @string
(str_esc_char) @string.escape
[
"{"
"}"
"("
")"
"[|"
"|]"
] @punctuation.bracket
(multstr_start) @punctuation.bracket
(multstr_end) @punctuation.bracket
(interpolation_start) @punctuation.bracket
(interpolation_end) @punctuation.bracket
(record_field) @variable.member
(builtin) @function.builtin
(fun_expr
pats: (pattern_fun
(ident) @variable.parameter))
(applicative
t1: (applicative
(record_operand) @function))

View file

@ -1,25 +0,0 @@
; inherits: python
((rule_definition) @indent.begin
(#set! indent.immediate 1))
((checkpoint_definition) @indent.begin
(#set! indent.immediate 1))
((rule_inheritance) @indent.begin
(#set! indent.immediate 1))
((rule_import
"with"
":") @indent.begin
(#set! indent.immediate 1))
((module_definition) @indent.begin
(#set! indent.immediate 1))
((directive) @indent.begin
(#set! indent.immediate 1))
; end indentation after last parameter node (no following ',')
(directive_parameters
(_) @indent.end .)

View file

@ -1,4 +0,0 @@
; inherits: python
(rule_definition
name: (identifier) @local.definition.type) @local.scope

View file

@ -1 +0,0 @@
; inherits python

View file

@ -1 +0,0 @@
; inherits: ecma,jsx

View file

@ -1 +0,0 @@
; inherits: ecma

View file

@ -1,47 +0,0 @@
(identifier) @variable.member
(constant) @constant
(modifier_function) @function
(modifier_predefined) @function.builtin
[
(condition)
(condition_end)
(condition_else)
] @keyword.conditional
(cobject) @type.builtin
[
"@import"
"INCLUDE_TYPOSCRIPT"
] @keyword.import
[
(comment)
(single_line_comment)
] @comment @spell
[
(string)
(multiline_value)
] @string
[
"="
">"
"<"
":="
"=<"
(condition_bool)
] @operator
"," @punctuation.delimiter
[
"("
")"
(block_punctuation)
] @punctuation.bracket

View file

@ -1,5 +0,0 @@
(block) @indent.begin
"}" @indent.branch @indent.end
(comment) @indent.ignore

View file

@ -1,13 +0,0 @@
(comment) @comment @spell
(keyword) @keyword
(tag
[
"{{"
"{{-"
"}}"
"-}}"
] @punctuation.special)
"|>" @operator

View file

@ -1,12 +0,0 @@
[
(world_items)
(world_body)
(interface_items)
(interface_body)
] @fold
(world_items
[
(use_item)
(import_item)
])+ @fold

View file

@ -1 +0,0 @@
(block) @fold

Some files were not shown because too many files have changed in this diff Show more