Support bash autoindenting (#24156)
Creates an indents.scm file for bash and adds regexes for `{increase,decrease}_indent_pattern` in `crates/languages/src/bash/config.toml` so that autoindent works as expected in bash Note that this PR does not attempt to handle all cases where indenting might be desired in bash. I am aiming to support ~80% of what people want while avoiding the more gnarly/edge cases like indented blocks in case statements and indenting for associative arrays. This is done with the explicit hope that someone (possibly from the community) more familiar with and passionate about bash can come through at a later date and handle those cases Closes #23628 Release Notes: - Add basic support for autoindent functionality in bash/shell files
This commit is contained in:
parent
dfd11c3d3b
commit
b6e680ea3d
4 changed files with 130 additions and 2 deletions
|
@ -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
|
||||
|
|
|
@ -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::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<AllLanguageSettings>(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<Buffer>, 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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
12
crates/languages/src/bash/indents.scm
Normal file
12
crates/languages/src/bash/indents.scm
Normal file
|
@ -0,0 +1,12 @@
|
|||
(function_definition
|
||||
"function"?
|
||||
body: (
|
||||
_
|
||||
"{" @start
|
||||
"}" @end
|
||||
)) @indent
|
||||
|
||||
(array
|
||||
"(" @start
|
||||
")" @end
|
||||
) @indent
|
Loading…
Add table
Add a link
Reference in a new issue