languages: Fix indentation for if/else statements in C/C++ without braces (#41670)
Closes #41179 Release Notes: - Fixed indentation for if/else statements in C/C++ without braces
This commit is contained in:
@@ -98,6 +98,7 @@ text.workspace = true
|
||||
theme = { workspace = true, features = ["test-support"] }
|
||||
tree-sitter-bash.workspace = true
|
||||
tree-sitter-c.workspace = true
|
||||
tree-sitter-cpp.workspace = true
|
||||
tree-sitter-css.workspace = true
|
||||
tree-sitter-go.workspace = true
|
||||
tree-sitter-python.workspace = true
|
||||
|
||||
+219
-12
@@ -395,10 +395,10 @@ mod tests {
|
||||
use language::{AutoindentMode, Buffer};
|
||||
use settings::SettingsStore;
|
||||
use std::num::NonZeroU32;
|
||||
use unindent::Unindent;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_c_autoindent(cx: &mut TestAppContext) {
|
||||
// cx.executor().set_block_on_ticks(usize::MAX..=usize::MAX);
|
||||
async fn test_c_autoindent_basic(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
let test_settings = SettingsStore::test(cx);
|
||||
cx.set_global(test_settings);
|
||||
@@ -413,23 +413,230 @@ mod tests {
|
||||
cx.new(|cx| {
|
||||
let mut buffer = Buffer::local("", cx).with_language(language, cx);
|
||||
|
||||
// empty function
|
||||
buffer.edit([(0..0, "int main() {}")], None, cx);
|
||||
|
||||
// indent inside braces
|
||||
let ix = buffer.len() - 1;
|
||||
buffer.edit([(ix..ix, "\n\n")], Some(AutoindentMode::EachLine), cx);
|
||||
assert_eq!(buffer.text(), "int main() {\n \n}");
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"int main() {\n \n}",
|
||||
"content inside braces should be indented"
|
||||
);
|
||||
|
||||
// indent body of single-statement if statement
|
||||
let ix = buffer.len() - 2;
|
||||
buffer.edit([(ix..ix, "if (a)\nb;")], Some(AutoindentMode::EachLine), cx);
|
||||
assert_eq!(buffer.text(), "int main() {\n if (a)\n b;\n}");
|
||||
buffer
|
||||
});
|
||||
}
|
||||
|
||||
// indent inside field expression
|
||||
let ix = buffer.len() - 3;
|
||||
#[gpui::test]
|
||||
async fn test_c_autoindent_if_else(cx: &mut TestAppContext) {
|
||||
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(cx, |s| {
|
||||
s.project.all_languages.defaults.tab_size = NonZeroU32::new(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
let language = crate::language("c", tree_sitter_c::LANGUAGE.into());
|
||||
|
||||
cx.new(|cx| {
|
||||
let mut buffer = Buffer::local("", cx).with_language(language, cx);
|
||||
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"body of if-statement without braces should be indented"
|
||||
);
|
||||
|
||||
let ix = buffer.len() - 4;
|
||||
buffer.edit([(ix..ix, "\n.c")], Some(AutoindentMode::EachLine), cx);
|
||||
assert_eq!(buffer.text(), "int main() {\n if (a)\n b\n .c;\n}");
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b
|
||||
.c;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"field expression (.c) should be indented further than the statement body"
|
||||
);
|
||||
|
||||
buffer.edit([(0..buffer.len(), "")], Some(AutoindentMode::EachLine), cx);
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a) a++;
|
||||
else b++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a) a++;
|
||||
else b++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"single-line if/else without braces should align at the same level"
|
||||
);
|
||||
|
||||
buffer.edit([(0..buffer.len(), "")], Some(AutoindentMode::EachLine), cx);
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b++;
|
||||
else
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b++;
|
||||
else
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"multi-line if/else without braces should indent statement bodies"
|
||||
);
|
||||
|
||||
buffer.edit([(0..buffer.len(), "")], Some(AutoindentMode::EachLine), cx);
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
if (b)
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
if (b)
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"nested if statements without braces should indent properly"
|
||||
);
|
||||
|
||||
buffer.edit([(0..buffer.len(), "")], Some(AutoindentMode::EachLine), cx);
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b++;
|
||||
else if (c)
|
||||
d++;
|
||||
else
|
||||
f++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b++;
|
||||
else if (c)
|
||||
d++;
|
||||
else
|
||||
f++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"else-if chains should align all conditions at same level with indented bodies"
|
||||
);
|
||||
|
||||
buffer.edit([(0..buffer.len(), "")], Some(AutoindentMode::EachLine), cx);
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a) {
|
||||
b++;
|
||||
} else
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a) {
|
||||
b++;
|
||||
} else
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"mixed braces should indent properly"
|
||||
);
|
||||
|
||||
buffer
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ path_suffixes = ["c"]
|
||||
line_comments = ["// "]
|
||||
decrease_indent_patterns = [
|
||||
{ pattern = "^\\s*\\{.*\\}?\\s*$", valid_after = ["if", "for", "while", "do", "switch", "else"] },
|
||||
{ pattern = "^\\s*else\\s*$", valid_after = ["if"] }
|
||||
{ pattern = "^\\s*else\\b", valid_after = ["if"] }
|
||||
]
|
||||
autoclose_before = ";:.,=}])>"
|
||||
brackets = [
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::{AppContext as _, BorrowAppContext, TestAppContext};
|
||||
use language::{AutoindentMode, Buffer};
|
||||
use settings::SettingsStore;
|
||||
use std::num::NonZeroU32;
|
||||
use unindent::Unindent;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_cpp_autoindent_basic(cx: &mut TestAppContext) {
|
||||
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(cx, |s| {
|
||||
s.project.all_languages.defaults.tab_size = NonZeroU32::new(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
let language = crate::language("cpp", tree_sitter_cpp::LANGUAGE.into());
|
||||
|
||||
cx.new(|cx| {
|
||||
let mut buffer = Buffer::local("", cx).with_language(language, cx);
|
||||
|
||||
buffer.edit([(0..0, "int main() {}")], None, cx);
|
||||
|
||||
let ix = buffer.len() - 1;
|
||||
buffer.edit([(ix..ix, "\n\n")], Some(AutoindentMode::EachLine), cx);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"int main() {\n \n}",
|
||||
"content inside braces should be indented"
|
||||
);
|
||||
|
||||
buffer
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_cpp_autoindent_if_else(cx: &mut TestAppContext) {
|
||||
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(cx, |s| {
|
||||
s.project.all_languages.defaults.tab_size = NonZeroU32::new(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
let language = crate::language("cpp", tree_sitter_cpp::LANGUAGE.into());
|
||||
|
||||
cx.new(|cx| {
|
||||
let mut buffer = Buffer::local("", cx).with_language(language, cx);
|
||||
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"body of if-statement without braces should be indented"
|
||||
);
|
||||
|
||||
let ix = buffer.len() - 4;
|
||||
buffer.edit([(ix..ix, "\n.c")], Some(AutoindentMode::EachLine), cx);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b
|
||||
.c;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"field expression (.c) should be indented further than the statement body"
|
||||
);
|
||||
|
||||
buffer.edit([(0..buffer.len(), "")], Some(AutoindentMode::EachLine), cx);
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a) a++;
|
||||
else b++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a) a++;
|
||||
else b++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"single-line if/else without braces should align at the same level"
|
||||
);
|
||||
|
||||
buffer.edit([(0..buffer.len(), "")], Some(AutoindentMode::EachLine), cx);
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b++;
|
||||
else
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b++;
|
||||
else
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"multi-line if/else without braces should indent statement bodies"
|
||||
);
|
||||
|
||||
buffer.edit([(0..buffer.len(), "")], Some(AutoindentMode::EachLine), cx);
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
if (b)
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
if (b)
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"nested if statements without braces should indent properly"
|
||||
);
|
||||
|
||||
buffer.edit([(0..buffer.len(), "")], Some(AutoindentMode::EachLine), cx);
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b++;
|
||||
else if (c)
|
||||
d++;
|
||||
else
|
||||
f++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a)
|
||||
b++;
|
||||
else if (c)
|
||||
d++;
|
||||
else
|
||||
f++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"else-if chains should align all conditions at same level with indented bodies"
|
||||
);
|
||||
|
||||
buffer.edit([(0..buffer.len(), "")], Some(AutoindentMode::EachLine), cx);
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
r#"
|
||||
int main() {
|
||||
if (a) {
|
||||
b++;
|
||||
} else
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
if (a) {
|
||||
b++;
|
||||
} else
|
||||
c++;
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"mixed braces should indent properly"
|
||||
);
|
||||
|
||||
buffer
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ path_suffixes = ["cc", "hh", "cpp", "h", "hpp", "cxx", "hxx", "c++", "ipp", "inl
|
||||
line_comments = ["// ", "/// ", "//! "]
|
||||
decrease_indent_patterns = [
|
||||
{ pattern = "^\\s*\\{.*\\}?\\s*$", valid_after = ["if", "for", "while", "do", "switch", "else"] },
|
||||
{ pattern = "^\\s*else\\s*$", valid_after = ["if"] }
|
||||
{ pattern = "^\\s*else\\b", valid_after = ["if"] }
|
||||
]
|
||||
autoclose_before = ";:.,=}])>"
|
||||
brackets = [
|
||||
|
||||
@@ -19,6 +19,7 @@ use crate::{
|
||||
|
||||
mod bash;
|
||||
mod c;
|
||||
mod cpp;
|
||||
mod css;
|
||||
mod go;
|
||||
mod json;
|
||||
|
||||
Reference in New Issue
Block a user