Indent statements under C/C++ case labels (#60758)
# Objective Fixes #60261 Nothing under a `case` gets indented in C or C++, and the next `case` doesn't come back out. It stays flat until you hit `editor: format`. ## Solution The indent queries had no rule for case labels. Added the same pair `cpp/indents.scm` uses for `access_specifier`: open an indent range at the label, close it at the switch's `}`, outdent on the next label. The part that got me: `@start` uses the *end* of the node you capture. Fine for `access_specifier`, which is just `public:`. But a `case_statement` swallows the statements under it, so capturing the node starts the range after the last one. Capture the `:` instead. `default:` is a `case_statement` too, so it comes along free. Only affects what happens after a label, so existing `case` alignment doesn't move. ## Testing `test_c_autoindent_switch_case` and `test_cpp_autoindent_switch_case` cover a plain case, fall-through labels and `default`. Both fail on main. The `access_specifier` tests still pass. Not mine, but worth knowing: `typescript::tests::test_outline` and `test_generator_function_outline` are flaky on main, failing about half my full `cargo test -p languages --lib` runs with or without this change. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Fixed statements under a `case` label not being indented in C and C++ ([#60261](https://github.com/zed-industries/zed/issues/60261)).
This commit is contained in:
1 parent
23bb2fc135
commit
aeeacf5439
4 files changed
+146
No files matched your search
@@ -17,6 +17,15 @@
|
||||
"{"
|
||||
"}" @end) @indent
|
||||
|
||||
(compound_statement
|
||||
(case_statement
|
||||
":" @start)
|
||||
"}" @end) @indent
|
||||
|
||||
(compound_statement
|
||||
(case_statement)
|
||||
(case_statement) @outdent)
|
||||
|
||||
(_
|
||||
"("
|
||||
")" @end) @indent
|
||||
|
||||
@@ -25,6 +25,15 @@
|
||||
(access_specifier)
|
||||
(access_specifier) @outdent)
|
||||
|
||||
(compound_statement
|
||||
(case_statement
|
||||
":" @start)
|
||||
"}" @end) @indent
|
||||
|
||||
(compound_statement
|
||||
(case_statement)
|
||||
(case_statement) @outdent)
|
||||
|
||||
(_
|
||||
"("
|
||||
")" @end) @indent
|
||||
|
||||
@@ -451,6 +451,70 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_c_autoindent_switch_case(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
let test_settings = SettingsStore::test(cx);
|
||||
cx.set_global(test_settings);
|
||||
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() {
|
||||
switch (a) {
|
||||
case 1:
|
||||
b++;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
c++;
|
||||
break;
|
||||
default:
|
||||
d++;
|
||||
}
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
switch (a) {
|
||||
case 1:
|
||||
b++;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
c++;
|
||||
break;
|
||||
default:
|
||||
d++;
|
||||
}
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"statements under a case label should be indented, and the next label outdented"
|
||||
);
|
||||
|
||||
buffer
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_c_autoindent_if_else(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
|
||||
@@ -16,6 +16,70 @@ mod tests {
|
||||
use std::num::NonZeroU32;
|
||||
use unindent::Unindent;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_cpp_autoindent_switch_case(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
let test_settings = SettingsStore::test(cx);
|
||||
cx.set_global(test_settings);
|
||||
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() {
|
||||
switch (a) {
|
||||
case 1:
|
||||
b++;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
c++;
|
||||
break;
|
||||
default:
|
||||
d++;
|
||||
}
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
)],
|
||||
Some(AutoindentMode::EachLine),
|
||||
cx,
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
r#"
|
||||
int main() {
|
||||
switch (a) {
|
||||
case 1:
|
||||
b++;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
c++;
|
||||
break;
|
||||
default:
|
||||
d++;
|
||||
}
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
"statements under a case label should be indented, and the next label outdented"
|
||||
);
|
||||
|
||||
buffer
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_cpp_autoindent_access_specifier(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
|
||||
Reference in new issue
Block a user