-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add rust support via tree-sitter #140
Conversation
Previously, placing the cursor on line 1 would highlight every elif and else in the whole block of code. % would jump to line 4, then % from there would cycle between lines 2, 4 and 6. 1 if noice: 2 if yeah: 3 pass 4 elif no: 5 pass 6 else: 7 pass 8 elif blah: 9 pass 10 else: 11 pass With the change, which I think the code had contemplated given there was already an unused `M.containing_scope(node, bufnr, info.key)` call, % will only move between ifs and elses that are in the same `@scope.if_`, and not to any inner scopes. Hence the example will have two mutually exclusive %-cycles: [1, 8, 10] and [2, 4, 6].
now the first | matches any contained return statements, and those returns do not match the surrounding `fn`.
Thanks for this! Re I don't know Rust, is it possible you could provide examples and desired matching, showing the caveats you mentioned so they can become test cases for my development? |
I would lean towards saying that's how rust's grammar is but it probably shouldn't be that way. Everyone thinks of else if as a single token, so much so that many languages combine them into elif/elsif. It is also not a particularly accurate description of the rust grammar that else if has an actual "if expression or block" because if that were really true you would be allowed to put any old expression in that slot and you are absolutely not. So any time anyone tries to build tree restructuring code for it they are going to come across this issue -- having to special case if_expressions within an else because they can't be replaced by any old expression and eg do not really make sense as a text object for "change in expression" etc. As noted in the query file there you can't even do that special casing in neovim today without more predicates being implemented, which is the second caveat and you can't solve it from matchup alone. Fixing the grammar would hit both. I'll have a look at that first. Re tests yes can do. |
Also higher order nodes in matchup should in general be pretty useless, because TS queries can already do ad hoc grouping like so: |
Apparently the predicate syntax is The other question I had now is if the cursor is here: As you point out there's no way to write a query that targets the "else if" specifically. But we want that combination to act like a single token for the purpose of matching somehow. This will require a bit of re-engineering as currently the "seed" token must be a single unnamed node. In case of Note my goal is to find a general way to support all languages. Rust is a good second target. Even if the PR you raised on the grammar is merged, it's good to resolve these concerns. I agree with you that in this case, grouping could work under a new grammar, I'm afraid that other languages will have similar cases. |
No it's definitely If you want a general way to resolve this, the best idea I have is to:
So the else would be targetable with % via |
I found a solution to highlighting (block (if_expression "if" @open.if_) @scope.if_)
(else_clause "else" @mid.if_.1 (block))
(else_clause
"else" @_start (if_expression "if" @_end)
(#make-range! "mid.if_.2" @_start @_end)) |
Just for linking: c39903d and https://github.com/nvim-treesitter/nvim-treesitter/blob/4df26673037a67686a4da91615cd129b39b60dd9/lua/nvim-treesitter/query.lua#L168 That's pretty cool! Nice solution. I'll try it out and patch this PR. |
Any update on getting this merged? Thanks! |
I've incorporated the rest of the queries from this PR. If there are any problems we can handle them in separate issues. |
Draft as this depends on and includes the previous PR #139
Supports:
if c {} else ...
where ... is either a block or another if_expression.let x = if y {} else {};
can't be matched lest an else-if branch introduce a new child scope.break 'label;
and also excluding break with a expressionbreak expr;
The if/else could be improved if the rust grammar is changed. I'm not sure if they would, because currently if_expression and if_let_expression are handled separately and adding another else_if and else_if_let would be a bit annoying to write, but it would make for easier to use output trees.