Improve behavior around word-based brackets in bash (#29700)

Closes #28414

Makes it so that `do`, `then`, `done`, `else`, etc are treated as
brackets in bash. They are not auto-closed *yet* as that requires
additional work to function properly, however they can now be toggled
between using `%` in vim. Additionally, newlines are inserted like they
are with regular brackets (`{}()[]""''`) when hitting enter between
them.

While `if <-> fi` `while/for <-> done` and `case <-> esac` are the
*logical* matching pairs, I've opted to instead match between `then <->
else/elif/fi` `do <-> done` and `in <-> esac` as these are the pairs
that delimit the sub-scope, and are more similar to the `{}` style
bracket pairs than `if <-> }` in a c-like syntax. This does cause some
wierd behavior with `else` in `if` expressions as it matches both with
the previous `then` as well as the following `fi`, so in this case

```bash
if true; then
   foo
else
   bar
f|i
```

after hitting `%` twice times (where cursor is `|`), the cursor will end
up on the `then` instead of back on the `fi` as hitting `%` on the else
will *always* navigate up to the `then`

Release Notes:

- vim: Improved behavior around word-based delimiters in bash (`do <->
done`, `then <-> fi`, etc) so they can be toggled between using `%`
This commit is contained in:
Ben Kunkle 2025-04-30 15:57:29 -04:00 committed by GitHub
parent 04c68dc0cf
commit fc920bf63d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 12 additions and 0 deletions

View file

@ -3,3 +3,10 @@
("{" @open "}" @close)
("\"" @open "\"" @close)
("`" @open "`" @close)
(("do" @open "done" @close) (#set! newline.only))
((case_statement ("in" @open "esac" @close)) (#set! newline.only))
((if_statement (elif_clause ("then" @open)) (else_clause ("else" @close))) (#set! newline.only))
((if_statement (else_clause ("else" @open)) "fi" @close) (#set! newline.only))
((if_statement ("then" @open) (elif_clause ("elif" @close))) (#set! newline.only))
((if_statement ("then" @open) (else_clause ("else" @close))) (#set! newline.only))
((if_statement ("then" @open "fi" @close)) (#set! newline.only))

View file

@ -10,6 +10,11 @@ brackets = [
{ start = "{", end = "}", close = true, newline = true },
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
{ start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
{ start = "do", end = "done", close = false, newline = true, not_in = ["comment", "string"] },
{ start = "then", end = "fi", close = false, newline = true, not_in = ["comment", "string"] },
{ start = "then", end = "else", close = false, newline = true, not_in = ["comment", "string"] },
{ start = "then", end = "elif", close = false, newline = true, not_in = ["comment", "string"] },
{ start = "in", end = "esac", close = false, newline = true, not_in = ["comment", "string"] },
]
### WARN: the following is not working when you insert an `elif` just before an else