From 58758fee610a3808dfaeafddd1b4b4242a7e42cd Mon Sep 17 00:00:00 2001 From: Triton171 Date: Wed, 30 Mar 2022 17:08:07 +0200 Subject: Indentation rework (#1562) * WIP: Rework indentation system * Add ComplexNode for context-aware indentation (including a proof of concept for assignment statements in rust) * Add switch statements to Go indents.toml (fixes the second half of issue #1523) Remove commented-out code * Migrate all existing indentation queries. Add more options to ComplexNode and use them to improve C/C++ indentation. * Add comments & replace Option> with Vec<_> * Add more detailed documentation for tree-sitter indentation * Improve code style in indent.rs * Use tree-sitter queries for indentation instead of TOML config. Migrate existing indent queries. * Add documentation for the new indent queries. Change xtask docgen to look for indents.scm instead of indents.toml * Improve code style in indent.rs. Fix an issue with the rust indent query. * Move indentation test sources to separate files. Add `#not-kind-eq?`, `#same-line?` and `#not-same-line` custom predicates. Improve the rust and c indent queries. * Fix indent test. Improve rust indent queries. * Move indentation tests to integration test folder. * Improve code style in indent.rs. Reuse tree-sitter cursors for indentation queries. * Migrate HCL indent query * Replace custom loading in indent tests with a designated languages.toml * Update indent query file name for --health command. * Fix single-space formatting in indent queries. * Add explanation for unwrapping. Co-authored-by: Triton171 --- book/src/guides/indent.md | 79 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 book/src/guides/indent.md (limited to 'book/src/guides') 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. -- cgit v1.2.3-70-g09d2