diff options
Diffstat (limited to 'book/src')
-rw-r--r-- | book/src/SUMMARY.md | 1 | ||||
-rw-r--r-- | book/src/guides/indent.md | 79 |
2 files changed, 80 insertions, 0 deletions
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 9e15eee3..ef214b12 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -16,3 +16,4 @@ - [Guides](./guides/README.md) - [Adding Languages](./guides/adding_languages.md) - [Adding Textobject Queries](./guides/textobject.md) + - [Adding Indent Queries](./guides/indent.md) diff --git a/book/src/guides/indent.md b/book/src/guides/indent.md new file mode 100644 index 00000000..235a30c4 --- /dev/null +++ b/book/src/guides/indent.md @@ -0,0 +1,79 @@ +# 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. + +## 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): + +- `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. + +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 + (#set! "scope" "all")) +``` + +## Capture Types + +- `@indent` (default scope `tail`): +Increase the indent level by 1. Multiple occurences 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. + +## 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: +```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). + +- `#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). + +- `#same-line?`/`#not-same-line?`: +The captures given by the 2 arguments must/must not start on the same line. |