diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 707fb43cc3b573772ef24b7fe7eea69a2ad3c8ec..20d976ad6c0e0a9c82fbaa681efea80f2873d375 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -12438,9 +12438,7 @@ impl Editor { cx: &mut Context, ) { 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.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.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.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.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.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) { @@ -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, diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 0da80a2a73f22afac7085b579494d708be2444a4..f497881531bf4ba39cb22aca4cf90923f7d10b81 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -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! {"