From fc920bf63d827a33691f6bd4e24bef271a743c0b Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Wed, 30 Apr 2025 15:57:29 -0400 Subject: [PATCH] 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 `%` --- crates/languages/src/bash/brackets.scm | 7 +++++++ crates/languages/src/bash/config.toml | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/crates/languages/src/bash/brackets.scm b/crates/languages/src/bash/brackets.scm index 62c875dec11946b49686527ac6f394bceb5a5b58..5ae73cdda76c3d0775ddb124c7b7343e5f2004de 100644 --- a/crates/languages/src/bash/brackets.scm +++ b/crates/languages/src/bash/brackets.scm @@ -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)) diff --git a/crates/languages/src/bash/config.toml b/crates/languages/src/bash/config.toml index b56628ee8f28d8354aff0a745b3e41e802dcbc97..07c5161acb934b475a1c265ef6e66327936256bc 100644 --- a/crates/languages/src/bash/config.toml +++ b/crates/languages/src/bash/config.toml @@ -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