Rewrite and refactor the guides

pull/5534/head
David-Else 1 year ago
parent 421b5ebace
commit dc6a0e3064

@ -1,4 +1,4 @@
# Guides
This section contains guides for adding new language server configurations,
tree-sitter grammars, textobject queries, etc.
tree-sitter grammars, textobject queries, and other similar items.

@ -1,45 +1,59 @@
# Adding languages
# Adding new languages to Helix
In order to add a new language to Helix, you will need to follow the steps
below.
## Language configuration
To add a new language, you need to add a `[[language]]` entry to the
`languages.toml` (see the [language configuration section]).
1. Add a new `[[language]]` entry in the `languages.toml` file and provide the
necessary configuration for the new language. For more information on
language configuration, refer to the
[language configuration section](../languages.md) of the documentation.
2. If you are adding a new language or updating an existing language server
configuration, run the command `cargo xtask docgen` to update the
[Language Support](../lang-support.md) documentation.
When adding a new language or Language Server configuration for an existing
language, run `cargo xtask docgen` to add the new configuration to the
[Language Support][lang-support] docs before creating a pull request.
When adding a Language Server configuration, be sure to update the
[Language Server Wiki][install-lsp-wiki] with installation notes.
> 💡 If you are adding a new Language Server configuration, make sure to update
> the
> [Language Server Wiki](https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers)
> with the installation instructions.
## Grammar configuration
If a tree-sitter grammar is available for the language, add a new `[[grammar]]`
entry to `languages.toml`.
You may use the `source.path` key rather than `source.git` with an absolute path
to a locally available grammar for testing, but switch to `source.git` before
submitting a pull request.
1. If a tree-sitter grammar is available for the new language, add a new
`[[grammar]]` entry to the `languages.toml` file.
2. If you are testing the grammar locally, you can use the `source.path` key
with an absolute path to the grammar. However, before submitting a pull
request, make sure to switch to using `source.git`.
## Queries
For a language to have syntax-highlighting and indentation among
other things, you have to add queries. Add a directory for your
language with the path `runtime/queries/<name>/`. The tree-sitter
[website](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#queries)
gives more info on how to write queries.
> NOTE: When evaluating queries, the first matching query takes
precedence, which is different from other editors like Neovim where
the last matching query supersedes the ones before it. See
[this issue][neovim-query-precedence] for an example.
## Common Issues
- If you get errors when running after switching branches, you may have to update the tree-sitter grammars. Run `hx --grammar fetch` to fetch the grammars and `hx --grammar build` to build any out-of-date grammars.
- If a parser is segfaulting or you want to remove the parser, make sure to remove the compiled parser in `runtime/grammar/<name>.so`
1. In order to provide syntax highlighting and indentation for the new language,
you will need to add queries.
2. Create a new directory for the language with the path
`runtime/queries/<name>/`.
3. Refer to the
[tree-sitter website](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#queries)
for more information on writing queries.
> 💡 In Helix, the first matching query takes precedence when evaluating
> queries, which is different from other editors such as Neovim where the last
> matching query supersedes the ones before it. See
> [this issue](https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090)
> for an example.
## Common issues
- If you encounter errors when running Helix after switching branches, you may
need to update the tree-sitter grammars. Run the command `hx --grammar fetch`
to fetch the grammars and `hx --grammar build` to build any out-of-date
grammars.
- If a parser is causing a segfault or you want to remove it, make sure to
remove the compiled parser located at `runtime/grammar/<name>.so`.
[language configuration section]: ../languages.md
[neovim-query-precedence]: https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090
[install-lsp-wiki]: https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers
[neovim-query-precedence]:
https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090
[install-lsp-wiki]:
https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers
[lang-support]: ../lang-support.md

@ -1,35 +1,33 @@
# Adding Indent Queries
Helix uses tree-sitter to correctly indent new lines. This requires
a tree-sitter grammar and an `indent.scm` query file placed in
`runtime/queries/{language}/indents.scm`. The indentation for a line
is calculated by traversing the syntax tree from the lowest node at the
beginning of the new line. Each of these nodes contributes to the total
indent when it is captured by the query (in what way depends on the name
of the capture).
Note that it matters where these added indents begin. For example,
multiple indent level increases that start on the same line only increase
the total indent level by 1.
Helix uses tree-sitter to correctly indent new lines. This requires a
tree-sitter grammar and an `indent.scm` query file placed in
`runtime/queries/{language}/indents.scm`. The indentation for a line is
calculated by traversing the syntax tree from the lowest node at the beginning
of the new line. Each of these nodes contributes to the total indent when it is
captured by the query (in what way depends on the name of the capture).
Note that it matters where these added indents begin. For example, multiple
indent level increases that start on the same line only increase the total
indent level by 1.
## Scopes
Added indents don't always apply to the whole node. For example, in most
cases when a node should be indented, we actually only want everything
except for its first line to be indented. For this, there are several
scopes (more scopes may be added in the future if required):
Added indents don't always apply to the whole node. For example, in most cases
when a node should be indented, we actually only want everything except for its
first line to be indented. For this, there are several scopes (more scopes may
be added in the future if required):
- `all`: This scope applies to the whole captured node. This is only different
from `tail` when the captured node is the first node on its line.
- `all`:
This scope applies to the whole captured node. This is only different from
`tail` when the captured node is the first node on its line.
- `tail`: This scope applies to everything except for the first line of the
captured node.
- `tail`:
This scope applies to everything except for the first line of the
captured node.
Every capture type has a default scope which should do the right thing in most
situations. When a different scope is required, this can be changed by using a
`#set!` declaration anywhere in the pattern:
Every capture type has a default scope which should do the right thing
in most situations. When a different scope is required, this can be
changed by using a `#set!` declaration anywhere in the pattern:
```scm
(assignment_expression
right: (_) @indent
@ -38,56 +36,54 @@ changed by using a `#set!` declaration anywhere in the pattern:
## Capture Types
- `@indent` (default scope `tail`):
Increase the indent level by 1. Multiple occurrences in the same line
don't stack. If there is at least one `@indent` and one `@outdent`
capture on the same line, the indent level isn't changed at all.
- `@outdent` (default scope `all`):
Decrease the indent level by 1. The same rules as for `@indent` apply.
- `@indent` (default scope `tail`): Increase the indent level by 1. Multiple
occurrences in the same line don't stack. If there is at least one `@indent`
and one `@outdent` capture on the same line, the indent level isn't changed at
all.
- `@extend`:
Extend the range of this node to the end of the line and to lines that
are indented more than the line that this node starts on. This is useful
for languages like Python, where for the purpose of indentation some nodes
(like functions or classes) should also contain indented lines that follow them.
- `@outdent` (default scope `all`): Decrease the indent level by 1. The same
rules as for `@indent` apply.
- `@extend.prevent-once`:
Prevents the first extension of an ancestor of this node. For example, in Python
a return expression always ends the block that it is in. Note that this only stops the
extension of the next `@extend` capture. If multiple ancestors are captured,
only the extension of the innermost one is prevented. All other ancestors are unaffected
(regardless of whether the innermost ancestor would actually have been extended).
- `@extend`: Extend the range of this node to the end of the line and to lines
that are indented more than the line that this node starts on. This is useful
for languages like Python, where for the purpose of indentation some nodes
(like functions or classes) should also contain indented lines that follow
them.
- `@extend.prevent-once`: Prevents the first extension of an ancestor of this
node. For example, in Python a return expression always ends the block that it
is in. Note that this only stops the extension of the next `@extend` capture.
If multiple ancestors are captured, only the extension of the innermost one is
prevented. All other ancestors are unaffected (regardless of whether the
innermost ancestor would actually have been extended).
## Predicates
In some cases, an S-expression cannot express exactly what pattern should be matched.
For that, tree-sitter allows for predicates to appear anywhere within a pattern,
similar to how `#set!` declarations work:
In some cases, an S-expression cannot express exactly what pattern should be
matched. For that, tree-sitter allows for predicates to appear anywhere within a
pattern, similar to how `#set!` declarations work:
```scm
(some_kind
(child_kind) @indent
(#predicate? arg1 arg2 ...)
)
```
The number of arguments depends on the predicate that's used.
Each argument is either a capture (`@name`) or a string (`"some string"`).
The following predicates are supported by tree-sitter:
- `#eq?`/`#not-eq?`:
The first argument (a capture) must/must not be equal to the second argument
(a capture or a string).
The number of arguments depends on the predicate that's used. Each argument is
either a capture (`@name`) or a string (`"some string"`). The following
predicates are supported by tree-sitter:
- `#eq?`/`#not-eq?`: The first argument (a capture) must/must not be equal to
the second argument (a capture or a string).
- `#match?`/`#not-match?`:
The first argument (a capture) must/must not match the regex given in the
second argument (a string).
- `#match?`/`#not-match?`: The first argument (a capture) must/must not match
the regex given in the second argument (a string).
Additionally, we support some custom predicates for indent queries:
- `#not-kind-eq?`:
The kind of the first argument (a capture) must not be equal to the second
argument (a string).
- `#not-kind-eq?`: The kind of the first argument (a capture) must not be equal
to the second argument (a string).
- `#same-line?`/`#not-same-line?`:
The captures given by the 2 arguments must/must not start on the same line.
- `#same-line?`/`#not-same-line?`: The captures given by the 2 arguments
must/must not start on the same line.

@ -1,21 +1,21 @@
# Adding Textobject Queries
Textobjects that are language specific ([like functions, classes, etc][textobjects])
require an accompanying tree-sitter grammar and a `textobjects.scm` query file
to work properly. Tree-sitter allows us to query the source code syntax tree
and capture specific parts of it. The queries are written in a lisp dialect.
More information on how to write queries can be found in the [official tree-sitter
documentation][tree-sitter-queries].
Helix supports textobjects that are language specific, such as functions,
classes, etc. These textobjects require an accompanying tree-sitter grammar and
a `textobjects.scm` query file to work properly. Tree-sitter allows us to query
the source code syntax tree and capture specific parts of it. The queries are
written in a lisp dialect. More information on how to write queries can be found
in the [official tree-sitter documentation][tree-sitter-queries].
Query files should be placed in `runtime/queries/{language}/textobjects.scm`
when contributing. Note that to test the query files locally you should put
them under your local runtime directory (`~/.config/helix/runtime` on Linux
when contributing to Helix. Note that to test the query files locally you should
put them under your local runtime directory (`~/.config/helix/runtime` on Linux
for example).
The following [captures][tree-sitter-captures] are recognized:
| Capture Name |
| --- |
| ------------------ |
| `function.inside` |
| `function.around` |
| `class.inside` |
@ -26,24 +26,28 @@ The following [captures][tree-sitter-captures] are recognized:
| `comment.inside` |
| `comment.around` |
[Example query files][textobject-examples] can be found in the helix GitHub repository.
[Example query files][textobject-examples] can be found in the Helix GitHub
repository.
## Queries for Textobject Based Navigation
[Tree-sitter based navigation][textobjects-nav] is done using captures in the
following order:
Tree-sitter based navigation in Helix is done using captures in the following
order:
- `object.movement`
- `object.around`
- `object.inside`
For example if a `function.around` capture has been already defined for a language
in it's `textobjects.scm` file, function navigation should also work automatically.
`function.movement` should be defined only if the node captured by `function.around`
doesn't make sense in a navigation context.
For example if a `function.around` capture has been already defined for a
language in its `textobjects.scm` file, function navigation should also work
automatically. `function.movement` should be defined only if the node captured
by `function.around` doesn't make sense in a navigation context.
[textobjects]: ../usage.md#textobjects
[textobjects-nav]: ../usage.md#tree-sitter-textobject-based-navigation
[tree-sitter-queries]: https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax
[tree-sitter-captures]: https://tree-sitter.github.io/tree-sitter/using-parsers#capturing-nodes
[textobject-examples]: https://github.com/search?q=repo%3Ahelix-editor%2Fhelix+filename%3Atextobjects.scm&type=Code&ref=advsearch&l=&l=
[tree-sitter-queries]:
https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax
[tree-sitter-captures]:
https://tree-sitter.github.io/tree-sitter/using-parsers#capturing-nodes
[textobject-examples]:
https://github.com/search?q=repo%3Ahelix-editor%2Fhelix+filename%3Atextobjects.scm&type=Code&ref=advsearch&l=&l=

Loading…
Cancel
Save