diff --git a/crates/languages/Cargo.toml b/crates/languages/Cargo.toml index 388a61e514..23f59beb17 100644 --- a/crates/languages/Cargo.toml +++ b/crates/languages/Cargo.toml @@ -93,3 +93,4 @@ tree-sitter-python.workspace = true tree-sitter-go.workspace = true tree-sitter-c.workspace = true tree-sitter-css.workspace = true +tree-sitter-bash.workspace = true diff --git a/crates/languages/src/bash.rs b/crates/languages/src/bash.rs index bc4b7be467..ef9a18a9c5 100644 --- a/crates/languages/src/bash.rs +++ b/crates/languages/src/bash.rs @@ -15,3 +15,103 @@ pub(super) fn bash_task_context() -> ContextProviderWithTasks { }, ])) } + +#[cfg(test)] +mod tests { + use gpui::{AppContext as _, BorrowAppContext, Context, TestAppContext}; + use language::{language_settings::AllLanguageSettings, AutoindentMode, Buffer}; + use settings::SettingsStore; + use std::num::NonZeroU32; + + #[gpui::test] + async fn test_bash_autoindent(cx: &mut TestAppContext) { + cx.executor().set_block_on_ticks(usize::MAX..=usize::MAX); + let language = crate::language("bash", tree_sitter_bash::LANGUAGE.into()); + cx.update(|cx| { + let test_settings = SettingsStore::test(cx); + cx.set_global(test_settings); + language::init(cx); + cx.update_global::(|store, cx| { + store.update_user_settings::(cx, |s| { + s.defaults.tab_size = NonZeroU32::new(2) + }); + }); + }); + + cx.new(|cx| { + let mut buffer = Buffer::local("", cx).with_language(language, cx); + + let expect_indents_to = + |buffer: &mut Buffer, cx: &mut Context, input: &str, expected: &str| { + buffer.edit( [(0..buffer.len(), input)], Some(AutoindentMode::EachLine), cx, ); + assert_eq!(buffer.text(), expected); + }; + + // indent function correctly + expect_indents_to( + &mut buffer, + cx, + "function name() {\necho \"Hello, World!\"\n}", + "function name() {\n echo \"Hello, World!\"\n}", + ); + + // indent if-else correctly + expect_indents_to( + &mut buffer, + cx, + "if true;then\nfoo\nelse\nbar\nfi", + "if true;then\n foo\nelse\n bar\nfi", + ); + + // indent if-elif-else correctly + expect_indents_to( + &mut buffer, + cx, + "if true;then\nfoo\nelif true;then\nbar\nelse\nbar\nfi", + "if true;then\n foo\nelif true;then\n bar\nelse\n bar\nfi", + ); + + // indent case-when-else correctly + expect_indents_to( + &mut buffer, + cx, + "case $1 in\nfoo) echo \"Hello, World!\";;\n*) echo \"Unknown argument\";;\nesac", + "case $1 in\n foo) echo \"Hello, World!\";;\n *) echo \"Unknown argument\";;\nesac", + ); + + // indent for-loop correctly + expect_indents_to( + &mut buffer, + cx, + "for i in {1..10};do\nfoo\ndone", + "for i in {1..10};do\n foo\ndone", + ); + + // indent while-loop correctly + expect_indents_to( + &mut buffer, + cx, + "while true; do\nfoo\ndone", + "while true; do\n foo\ndone", + ); + + // indent array correctly + expect_indents_to( + &mut buffer, + cx, + "array=(\n1\n2\n3\n)", + "array=(\n 1\n 2\n 3\n)", + ); + + // indents non-"function" function correctly + expect_indents_to( + &mut buffer, + cx, + "foo() {\necho \"Hello, World!\"\n}", + "foo() {\n echo \"Hello, World!\"\n}", + ); + + buffer + }); + } +} diff --git a/crates/languages/src/bash/config.toml b/crates/languages/src/bash/config.toml index 08bb8ee095..91d01d6270 100644 --- a/crates/languages/src/bash/config.toml +++ b/crates/languages/src/bash/config.toml @@ -6,8 +6,23 @@ line_comments = ["# "] first_line_pattern = '^#!.*\b(?:ash|bash|dash|sh|zsh)\b' brackets = [ { start = "[", end = "]", close = true, newline = false }, - { start = "(", end = ")", close = true, newline = false }, - { start = "{", end = "}", close = true, newline = false }, + { start = "(", end = ")", close = true, newline = true }, + { 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"] }, ] + +### WARN: the following is not working when you insert an `elif` just before an else +### example: (^ is cursor after hitting enter) +### ``` +### if true; then +### foo +### elif +### ^ +### else +### bar +### fi +### ``` +increase_indent_pattern = "(\\s*|;)(do|then|in|else|elif)\\b.*$" +decrease_indent_pattern = "(\\s*|;)(fi|done|esac|else|elif)\\b.*$" +# make sure to test each line mode & block mode diff --git a/crates/languages/src/bash/indents.scm b/crates/languages/src/bash/indents.scm new file mode 100644 index 0000000000..acdcddabfe --- /dev/null +++ b/crates/languages/src/bash/indents.scm @@ -0,0 +1,12 @@ +(function_definition + "function"? + body: ( + _ + "{" @start + "}" @end + )) @indent + +(array + "(" @start + ")" @end + ) @indent