@@ -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! {"