From dc6a0e3064afefce39e102f886df439a5d99193d Mon Sep 17 00:00:00 2001 From: David-Else <12832280+David-Else@users.noreply.github.com> Date: Sat, 14 Jan 2023 16:37:42 +0000 Subject: [PATCH] Rewrite and refactor the guides --- book/src/guides/README.md | 2 +- book/src/guides/adding_languages.md | 78 +++++++++++-------- book/src/guides/indent.md | 114 ++++++++++++++-------------- book/src/guides/textobject.md | 42 +++++----- 4 files changed, 125 insertions(+), 111 deletions(-) diff --git a/book/src/guides/README.md b/book/src/guides/README.md index e0c44ce7d..c25768e68 100644 --- a/book/src/guides/README.md +++ b/book/src/guides/README.md @@ -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. diff --git a/book/src/guides/adding_languages.md b/book/src/guides/adding_languages.md index 6598b9bf7..3a59b5fda 100644 --- a/book/src/guides/adding_languages.md +++ b/book/src/guides/adding_languages.md @@ -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//`. 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/.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//`. +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/.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 diff --git a/book/src/guides/indent.md b/book/src/guides/indent.md index 0e2592897..c12f9fef6 100644 --- a/book/src/guides/indent.md +++ b/book/src/guides/indent.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. diff --git a/book/src/guides/textobject.md b/book/src/guides/textobject.md index 8a2173547..be8d797a3 100644 --- a/book/src/guides/textobject.md +++ b/book/src/guides/textobject.md @@ -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=