Fix title/camelCase commands stripping leading indentation Fixes (#50523)
Fixes: #48945 Description: The convert:to-title-case, convert:to-upper-camel-case, and convert:to-lower-camel-case editor commands were stripping leading whitespace from each line of a multi-line selection. Root cause: The conversion functions split on whitespace using .split_whitespace() and then joined the resulting words, discarding any leading spaces/tabs before the first word on each line. Fix: Each line now preserves its leading whitespace by capturing and re-prepending it before applying the case conversion. Tests: Added test cases covering multi-line selections with indentation for all three commands. Video : [bug1fix.webm](https://github.com/user-attachments/assets/f4d25c55-bc6d-44e6-a989-7d9b4bc59ac9) Release Notes: - Fixed trailing whitespace handling on text case changes
This commit is contained in:
1 parent
47b253fdaa
commit
06b9155491
2 files changed
+97
-10
No files matched your search
+26
-10
@@ -12438,9 +12438,7 @@ impl Editor {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.manipulate_text(window, cx, |text| {
|
||||
text.split('\n')
|
||||
.map(|line| line.to_case(Case::Title))
|
||||
.join("\n")
|
||||
Self::convert_text_case(text, Case::Title)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12450,7 +12448,9 @@ impl Editor {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
|
||||
self.manipulate_text(window, cx, |text| {
|
||||
Self::convert_text_case(text, Case::Snake)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn convert_to_kebab_case(
|
||||
@@ -12459,7 +12459,9 @@ impl Editor {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
|
||||
self.manipulate_text(window, cx, |text| {
|
||||
Self::convert_text_case(text, Case::Kebab)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn convert_to_upper_camel_case(
|
||||
@@ -12469,9 +12471,7 @@ impl Editor {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.manipulate_text(window, cx, |text| {
|
||||
text.split('\n')
|
||||
.map(|line| line.to_case(Case::UpperCamel))
|
||||
.join("\n")
|
||||
Self::convert_text_case(text, Case::UpperCamel)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12481,7 +12481,9 @@ impl Editor {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
|
||||
self.manipulate_text(window, cx, |text| {
|
||||
Self::convert_text_case(text, Case::Camel)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn convert_to_opposite_case(
|
||||
@@ -12509,7 +12511,9 @@ impl Editor {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
|
||||
self.manipulate_text(window, cx, |text| {
|
||||
Self::convert_text_case(text, Case::Sentence)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
|
||||
@@ -12540,6 +12544,18 @@ impl Editor {
|
||||
})
|
||||
}
|
||||
|
||||
fn convert_text_case(text: &str, case: Case) -> String {
|
||||
text.lines()
|
||||
.map(|line| {
|
||||
let trimmed_start = line.trim_start();
|
||||
let leading = &line[..line.len() - trimmed_start.len()];
|
||||
let trimmed = trimmed_start.trim_end();
|
||||
let trailing = &trimmed_start[trimmed.len()..];
|
||||
format!("{}{}{}", leading, trimmed.to_case(case), trailing)
|
||||
})
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
pub fn convert_to_rot47(
|
||||
&mut self,
|
||||
_: &ConvertToRot47,
|
||||
|
||||
@@ -6268,6 +6268,77 @@ async fn test_manipulate_text(cx: &mut TestAppContext) {
|
||||
«HeLlO, wOrLD!ˇ»
|
||||
"});
|
||||
|
||||
// Test that case conversions backed by `to_case` preserve leading/trailing whitespace.
|
||||
cx.set_state(indoc! {"
|
||||
« hello worldˇ»
|
||||
"});
|
||||
cx.update_editor(|e, window, cx| e.convert_to_title_case(&ConvertToTitleCase, window, cx));
|
||||
cx.assert_editor_state(indoc! {"
|
||||
« Hello Worldˇ»
|
||||
"});
|
||||
|
||||
cx.set_state(indoc! {"
|
||||
« hello worldˇ»
|
||||
"});
|
||||
cx.update_editor(|e, window, cx| {
|
||||
e.convert_to_upper_camel_case(&ConvertToUpperCamelCase, window, cx)
|
||||
});
|
||||
cx.assert_editor_state(indoc! {"
|
||||
« HelloWorldˇ»
|
||||
"});
|
||||
|
||||
cx.set_state(indoc! {"
|
||||
« hello worldˇ»
|
||||
"});
|
||||
cx.update_editor(|e, window, cx| {
|
||||
e.convert_to_lower_camel_case(&ConvertToLowerCamelCase, window, cx)
|
||||
});
|
||||
cx.assert_editor_state(indoc! {"
|
||||
« helloWorldˇ»
|
||||
"});
|
||||
|
||||
cx.set_state(indoc! {"
|
||||
« hello worldˇ»
|
||||
"});
|
||||
cx.update_editor(|e, window, cx| e.convert_to_snake_case(&ConvertToSnakeCase, window, cx));
|
||||
cx.assert_editor_state(indoc! {"
|
||||
« hello_worldˇ»
|
||||
"});
|
||||
|
||||
cx.set_state(indoc! {"
|
||||
« hello worldˇ»
|
||||
"});
|
||||
cx.update_editor(|e, window, cx| e.convert_to_kebab_case(&ConvertToKebabCase, window, cx));
|
||||
cx.assert_editor_state(indoc! {"
|
||||
« hello-worldˇ»
|
||||
"});
|
||||
|
||||
cx.set_state(indoc! {"
|
||||
« hello worldˇ»
|
||||
"});
|
||||
cx.update_editor(|e, window, cx| {
|
||||
e.convert_to_sentence_case(&ConvertToSentenceCase, window, cx)
|
||||
});
|
||||
cx.assert_editor_state(indoc! {"
|
||||
« Hello worldˇ»
|
||||
"});
|
||||
|
||||
cx.set_state(indoc! {"
|
||||
« hello world\t\tˇ»
|
||||
"});
|
||||
cx.update_editor(|e, window, cx| e.convert_to_title_case(&ConvertToTitleCase, window, cx));
|
||||
cx.assert_editor_state(indoc! {"
|
||||
« Hello World\t\tˇ»
|
||||
"});
|
||||
|
||||
cx.set_state(indoc! {"
|
||||
« hello world\t\tˇ»
|
||||
"});
|
||||
cx.update_editor(|e, window, cx| e.convert_to_snake_case(&ConvertToSnakeCase, window, cx));
|
||||
cx.assert_editor_state(indoc! {"
|
||||
« hello_world\t\tˇ»
|
||||
"});
|
||||
|
||||
// Test selections with `line_mode() = true`.
|
||||
cx.update_editor(|editor, _window, _cx| editor.selections.set_line_mode(true));
|
||||
cx.set_state(indoc! {"
|
||||
|
||||
Reference in new issue
Block a user