diff options
| author | Christian Clason <c.clason@uni-graz.at> | 2025-05-05 11:00:16 +0200 |
|---|---|---|
| committer | Christian Clason <c.clason@uni-graz.at> | 2025-05-12 18:43:41 +0200 |
| commit | e8bfe271b0da136048cdf20128b758ec87318479 (patch) | |
| tree | 7ff4f564acf75128647e4d9dfb6c3287623acdea | |
| parent | feat(parsers): update t32, query, markdown, markdown_inline, meson, hyprlang,... (diff) | |
| download | nvim-treesitter-e8bfe271b0da136048cdf20128b758ec87318479.tar nvim-treesitter-e8bfe271b0da136048cdf20128b758ec87318479.tar.gz nvim-treesitter-e8bfe271b0da136048cdf20128b758ec87318479.tar.bz2 nvim-treesitter-e8bfe271b0da136048cdf20128b758ec87318479.tar.lz nvim-treesitter-e8bfe271b0da136048cdf20128b758ec87318479.tar.xz nvim-treesitter-e8bfe271b0da136048cdf20128b758ec87318479.tar.zst nvim-treesitter-e8bfe271b0da136048cdf20128b758ec87318479.zip | |
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.
| -rw-r--r-- | .github/PULL_REQUEST_TEMPLATE/new_language.md | 45 | ||||
| -rw-r--r-- | .github/pull_request_template.md | 5 | ||||
| -rw-r--r-- | .tsqueryrc.json | 16 | ||||
| -rw-r--r-- | CONTRIBUTING.md | 308 | ||||
| -rw-r--r-- | README.md | 77 | ||||
| -rw-r--r-- | TODO.md | 2 | ||||
| -rw-r--r-- | doc/nvim-treesitter.txt | 233 | ||||
| -rw-r--r-- | lua/nvim-treesitter/health.lua | 2 |
8 files changed, 396 insertions, 292 deletions
diff --git a/.github/PULL_REQUEST_TEMPLATE/new_language.md b/.github/PULL_REQUEST_TEMPLATE/new_language.md new file mode 100644 index 000000000..0f814f0f0 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/new_language.md @@ -0,0 +1,45 @@ +<!-- + 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://... + +<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 +--> diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..1f5207d98 --- /dev/null +++ b/.github/pull_request_template.md @@ -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> +--> diff --git a/.tsqueryrc.json b/.tsqueryrc.json index 129550b46..6d020e987 100644 --- a/.tsqueryrc.json +++ b/.tsqueryrc.json @@ -129,14 +129,14 @@ "fold": "fold this node" }, "indents": { - "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)" + "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", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 845891459..983499e81 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,13 +1,16 @@ # 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! - -The main goal of `nvim-treesitter` is to provide a framework to easily install parsers and queries. - -Depending on which part of the plugin you want to contribute to, please read the appropriate section. +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. ## Parsers @@ -34,12 +37,14 @@ zimbu = { } ``` -**Note:** 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. +>[!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. -**Note:** To qualify for Tier 1 ("stable"), a parser needs to - * make 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; - * include and maintain reference queries. +>[!NOTE] +> To qualify for Tier 1 ("stable"), a parser needs to +> * make 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; +> * include and maintain reference queries. 2. If the parser name is not the same as the Vim filetype, add an entry to the `filetypes` table in `plugin/filetypes.lua`: @@ -47,30 +52,41 @@ zimbu = { zimbu = { 'zu' }, ``` -**Note: We only support external scanners written in C for portability reasons.** +>[!IMPORTANT] +> Only external scanners written in C are supported for portability reasons. -## Queries +3. Update the list of [supported languages] by running `make docs` (or `./scripts/update-readme.lua` if on Windows). + +4. Test if both `:TSInstall zimbu` and `:TSInstallFromGrammar zimbu` work without errors (`:checkhealth treesitter` or `./scripts/check-parsers.lua zimbu`). + +>[!IMPORTANT] +> You also need to add queries in order for the parser to actually be useful! + +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`. -Contributing to queries for an existing parser is basically modifying one of the `runtime/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). +## Queries -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 provided by `nvim-treesitter`: +To add (or edit existing) queries, create a corresponding `runtime/queries/zimbu/*.scm` file: -- `highlights.scm`: used for syntax highlighting, using the `highlight` module. +- `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). -- `textobjects.scm`: used to define text objects. -- `folds.scm`: used to define folds. -- `injections.scm`: used to define injections. +- `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`. -For these types there is a _norm_ you will have to follow so that features work fine. -Here are some global advices: +>[!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. -- Examples of queries can be found in [runtime/queries/](runtime/queries/) -- For highlights, all matching patterns are applied, with the last one determining the visible capture & highlight. -- For injections, try your best to ensure that each captured node is only matched by a single pattern. -- If the [parser is included in `nvim-treesitter`](https://github.com/nvim-treesitter/nvim-treesitter/SUPPORTED_LANGUAGES.md`) and installed with `:TSInstall`, you can use Neovim's developer tools (`:checkhealth`, `:InspectTree`, `:EditQuery`, `:Inspect`) to test your queries. +>[!TIP] +> Before opening a PR, run `make query` to format, lint, and check all queries. #### Inheriting languages @@ -96,7 +112,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 @@ -255,45 +274,179 @@ 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 node’s 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 + +```query +@fold ; fold this node +``` + +### 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 @@ -302,7 +455,7 @@ 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 or any other purpose). These queries -are only provided for (limited) backwards compatibility. +are only provided for limited backwards compatibility. ```query @local.definition ; various definitions @@ -349,58 +502,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 -@injection.filename ; indicates that the captured node’s 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` -``` - -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 @@ -15,14 +15,16 @@ </p> </div> -# WARNING -**This branch is a [full, incompatible, rewrite of `nvim-treesitter`](https://github.com/nvim-treesitter/nvim-treesitter/issues/4767) and [work in progress](TODO.md).** The **stable** branch is [`master`](https://github.com/nvim-treesitter/nvim-treesitter/tree/master). +>[!WARNING] +> This branch is a [full, incompatible, rewrite of `nvim-treesitter`](https://github.com/nvim-treesitter/nvim-treesitter/issues/4767) and [work in progress](TODO.md). The **stable** branch is [`master`](https://github.com/nvim-treesitter/nvim-treesitter/tree/master). 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. +For details on these and how to help improving them, see [CONTRIBUTING.md](./CONTRIBUTING.md). + # Quickstart ## Requirements @@ -37,7 +39,7 @@ The `nvim-treesitter` plugin provides 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 `parser.lua` table). **When upgrading the plugin, you must make sure that all installed parsers are updated to the latest version** via `:TSUpdate`. +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 [lazy.nvim](https://github.com/folke/lazy.nvim) ```lua @@ -46,7 +48,8 @@ require('lazy').setup( ) ``` -**NOTE: This plugin does not support lazy-loading.** +>[!IMPORTANT] +> This plugin does not support lazy-loading. ## Setup @@ -67,7 +70,14 @@ Parsers and queries can then be installed with 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"), adapt [this script](scripts/install-parsers.lua) to your needs. +(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"), use something like +```lua +local done = nil +require('nvim-treesitter').install({ 'rust', 'javascript', 'zig' }, function(success) + done = success +end) +vim.wait(3000000, function() return done ~= nil end) +``` Check [`:h nvim-treesitter-commands`](doc/nvim-treesitter.txt) for a list of all available commands. @@ -75,7 +85,7 @@ Check [`:h nvim-treesitter-commands`](doc/nvim-treesitter.txt) for a list of all 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. -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 the an existing one, please see our [contributing guide](CONTRIBUTING.md). +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). 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). @@ -134,13 +144,12 @@ callback = function() require('nvim-treesitter.parsers').zimbu = { install_info = { url = 'https://github.com/zimbulang/tree-sitter-zimbu', - files = { 'src/parser.c' }, -- note that some parsers also require src/scanner.c 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 = true, -- only needed if parser has npm dependencies + 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` }, } end}) @@ -150,11 +159,10 @@ Alternatively, if you have a local checkout, you can instead use ```lua install_info = { path = '~/parsers/tree-sitter-zimbu', - files = { 'src/parser.c' }, -- note that some parsers also require src/scanner.c -- optional entries - 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 = true, -- only needed if parser has npm dependencies + location = 'parser', + generate = true, + generate_from_json = false, }, ``` This will always use the state of the directory as-is (i.e., `branch` and `revision` will be ignored). @@ -169,7 +177,8 @@ If Neovim does not detect your language's filetype by default, you can use [Neov 3. Start `nvim` and `:TSInstall zimbu`. -**Note:** Parsers using external scanner need to be written in C. C++ scanners are no longer supported. +>[!IMPORTANT] +> Parsers using external scanner need to be written in C. ### Modifying parsers @@ -183,47 +192,9 @@ end}) ## Adding queries -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`. +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). E.g., to add queries for `zimbu`, put `highlights.scm` etc. under ```lua vim.fn.stdpath('data') .. 'site/queries/zimbu' ``` - -# 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`. - -#### 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 `:= vim.api.nvim_get_runtime_file('parser', 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 want to use a mirror instead of "https://github.com/" - -In your Lua config: - -```lua -for _, config in pairs(require("nvim-treesitter.parsers")) do - config.install_info.url = config.install_info.url:gsub("https://github.com/", "something else") -end - -require'nvim-treesitter'.setup { - -- - -- -} -``` @@ -6,8 +6,6 @@ This document lists the planned and finished changes in this rewrite towards [Nv - [ ] **`install.lua`:** migrate to async v2 - [ ] **tests:** remove custom crate, plenary dependency -- [ ] **documentation:** consolidate, autogenerate? -- [ ] **documentation:** migration guide - [ ] **indents:** rewrite (Helix or Zed compatible) - [ ] **textobjects:** include simple(!) `node`, `scope` (using `locals`) objects diff --git a/doc/nvim-treesitter.txt b/doc/nvim-treesitter.txt index f0abcc779..f95872177 100644 --- a/doc/nvim-treesitter.txt +++ b/doc/nvim-treesitter.txt @@ -11,16 +11,14 @@ Authors: Type |gO| to see the table of contents. ============================================================================== -INTRODUCTION *nvim-treesitter-intro* +INTRODUCTION *nvim-treesitter-intro* Nvim-treesitter provides functionalities for managing treesitter parsers and -compatible queries for core features (highlighting, injections, fold, indent). - -WARNING: This is work in progress and requires the latest commit on Neovim -`master`. +compatible queries for core features (highlighting, injections, folds, +indents). ============================================================================== -QUICK START *nvim-treesitter-quickstart* +QUICK START *nvim-treesitter-quickstart* To configure `nvim-treesitter`, put this in your `init.lua` file: >lua @@ -36,156 +34,141 @@ 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' } + require'nvim-treesitter'.install { 'rust', 'javascript', 'zig' } < -(This is a no-op if the parsers are already installed.) - 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()' + -- indentation, provided by nvim-treesitter + vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" + end, + }) +< ============================================================================== -COMMANDS *nvim-treesitter-commands* +COMMANDS *nvim-treesitter-commands* - *:TSInstall* -:TSInstall {language} ... ~ +:TSInstall {language} *:TSInstall* -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. +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 of the parser(s) are already installed. Installation is performed +asynchronously. Use *:TSInstall!* to force installation even if a parser is +already installed. - *:TSUpdate* -:TSUpdate {language} ... ~ +:TSInstallFromGrammar {language} *:TSInstallFromGrammar* -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. +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). - *:TSUninstall* -:TSUninstall {language} ... ~ +:TSUpdate [{language}] *:TSUpdate* -Deletes the parser for one or more {language}. You can use 'all' for language -to uninstall all parsers. +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. -============================================================================== -INDENTATION *nvim-treesitter-indentation* +Note: It is recommended to add this command as a build step in your plugin +manager. -Indentation based on treesitter for the |=| operator. -NOTE: this is an experimental feature and will be upstreamed to Neovim when -stable. +:TSUninstall {language} *:TSUninstall* -To enable it for a supported parser, add the following to a corresponding -`FileType` autocommand or `ftplugin/<lang>.lua`: >lua +Deletes the parser for one or more {language}, or all parsers with `all`. - vim.bo.indentexpr = 'v.lua:require'nvim-treesitter'.indentexpr()' +:TSLog *:TSLog* -< +Shows all messages from previous install, update, or uninstall operations. -Indentation for a language is controlled by `indents.scm` queries. The -following captures are supported: +============================================================================== +API *nvim-treesitter-api* +setup({opts}) *nvim-treesitter.setup()* -`@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. + Configure installation options. Needs to be specified before any + installation operation. -`@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. + Note: You only need to call `setup` if you want to set non-default + options! ->query - ( - (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. + Parameters: ~ + • {opts} `(table?)` Optional parameters: + • {install_dir} (`string?`, default `stdpath('data')/site/`) + directory to install parsers and queries to. Note: will be + appended to |runtimepath|. + • {ignore_install} (`string[]?`) list of languages to never + install even if specified for an installation operation. + (Useful when specifying tiers instead of individual + languages.) -eg for python: ->query - ((if_statement) @indent.begin - (#set! indent.immediate 1)) -< +install({languages}, {opts}, {callback}) *nvim-treesitter.install()* -Will allow: ->python - if True:<CR> - # Auto indent to here + Download, compile, and install the specified treesitter parsers and copy + the corresponding queries to a directory on |runtimepath|, enabling their + use in Neovim. -`@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. + Note: This operation is performed asynchronously by default. For + synchronous operation (e.g., in a bootstrapping script), you need to + provide a suitable {callback}: >lua + local done = nil + require('nvim-treesitter').install({ 'rust', 'javascript', 'zig' }, + function(success) + done = success + end) + vim.wait(3000000, function() return done ~= nil end) +< + 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). + • {callback} `(function?`) Callback for synchronous execution. -`@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. +uninstall({languages}) *nvim-treesitter.uninstall()* -`@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 + Remove the parser and queries for the specified language(s). -> - 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. ->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. + Parameters: ~ + • {languages} `(string[]|string)` (List of) languages or tiers (`stable`, + `unstable`) to update. -For example in python: +update({languages}, {callback}) *nvim-treesitter.update()* ->python - if (a > b and - c < d): - pass + Update the parsers and queries if older than the revision specified in the + manifest. -Is not correct, whereas ->python - if (a > b and - c < d): - pass + Note: This operation is performed asynchronously by default. For + synchronous operation (e.g., in a bootstrapping script), you need to + provide a suitable {callback}: >lua + local done = nil + require('nvim-treesitter').update(), + function(success) + done = success + end) + vim.wait(3000000, function() return done ~= nil end) +< + Parameters: ~ + • {languages} `(string[]|string)` (List of) languages or tiers to + uninstall. + • {callback} `(function?`) Callback for synchronous execution. -Would be correctly indented. This behavior may be chosen using -`indent.avoid_last_matching_next`. Eg. +indentexpr() *nvim-treesitter.indentexpr()* ->query - (if_statement - condition: (parenthesized_expression) @indent.align - (#set! indent.open_delimiter "(") - (#set! indent.close_delimiter ")") - (#set! indent.avoid_last_matching_next 1) - ) + Used to enable treesitter indentation for a language via >lua + vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" < -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. vim:tw=78:ts=8:expandtab:noet:ft=help:norl: diff --git a/lua/nvim-treesitter/health.lua b/lua/nvim-treesitter/health.lua index 8ca51814e..6904899f6 100644 --- a/lua/nvim-treesitter/health.lua +++ b/lua/nvim-treesitter/health.lua @@ -7,7 +7,7 @@ local health = vim.health local M = {} local NVIM_TREESITTER_MINIMUM_ABI = 13 -local TREE_SITTER_MIN_VER = { 0, 25, 1 } +local TREE_SITTER_MIN_VER = { 0, 25, 4 } ---@param name string ---@return table? |
