Fix text transformation commands for multiple line, single selection cases (#3060)

Joseph T. Lyons created

If you highlight the following block of text (with a single selection):

```
The quick brown
fox jumps over
the lazy dog
```

and run `editor: convert to upper camel case`, you'll get:

```
TheQuickBrown
foxJumpsOver
theLazyDog
```

instead of:

```
TheQuickBrown
FoxJumpsOver
TheLazyDog
```

The same thing happens for `editor: convert to title case`. This happens
because [`to_case` crate](https://crates.io/crates/convert_case) doesn't
allow the user to define '\n' as a boundary. I wanted to fix this at the
lib level, so I filled [an
issue](https://github.com/rutrum/convert-case/issues/16) but I never
heard back. What's strange is VS Code and Sublime I think both exhibit
the same output as we do currently, but I don't personally think this
feels right (happy to hear opposing opinions). I'm just doing the naive
thing to hack around this limitation of the `to_case` crate.

I did some testing and it seems I only need to adjust `editor: convert
to title case` and `editor: convert to upper camel case`. The way the
other transformations are implemented in `to_case` don't seem to have
this issue.

Release Notes:

- Fixed a bug where running certain text transfomration commands on a
single selection covering multiple lines would not transform all
selected lines as expected.

Change summary

crates/editor/src/editor.rs       | 16 ++++++++++++++--
crates/editor/src/editor_tests.rs | 28 ++++++++++++++++++++++++++++
2 files changed, 42 insertions(+), 2 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -4653,7 +4653,13 @@ impl Editor {
     }
 
     pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext<Self>) {
-        self.manipulate_text(cx, |text| text.to_case(Case::Title))
+        self.manipulate_text(cx, |text| {
+            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
+            // https://github.com/rutrum/convert-case/issues/16
+            text.split("\n")
+                .map(|line| line.to_case(Case::Title))
+                .join("\n")
+        })
     }
 
     pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext<Self>) {
@@ -4669,7 +4675,13 @@ impl Editor {
         _: &ConvertToUpperCamelCase,
         cx: &mut ViewContext<Self>,
     ) {
-        self.manipulate_text(cx, |text| text.to_case(Case::UpperCamel))
+        self.manipulate_text(cx, |text| {
+            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
+            // https://github.com/rutrum/convert-case/issues/16
+            text.split("\n")
+                .map(|line| line.to_case(Case::UpperCamel))
+                .join("\n")
+        })
     }
 
     pub fn convert_to_lower_camel_case(

crates/editor/src/editor_tests.rs 🔗

@@ -2792,6 +2792,34 @@ async fn test_manipulate_text(cx: &mut TestAppContext) {
         «hello worldˇ»
     "});
 
+    // Test multiple line, single selection case
+    // Test code hack that covers the fact that to_case crate doesn't support '\n' as a word boundary
+    cx.set_state(indoc! {"
+        «The quick brown
+        fox jumps over
+        the lazy dogˇ»
+    "});
+    cx.update_editor(|e, cx| e.convert_to_title_case(&ConvertToTitleCase, cx));
+    cx.assert_editor_state(indoc! {"
+        «The Quick Brown
+        Fox Jumps Over
+        The Lazy Dogˇ»
+    "});
+
+    // Test multiple line, single selection case
+    // Test code hack that covers the fact that to_case crate doesn't support '\n' as a word boundary
+    cx.set_state(indoc! {"
+        «The quick brown
+        fox jumps over
+        the lazy dogˇ»
+    "});
+    cx.update_editor(|e, cx| e.convert_to_upper_camel_case(&ConvertToUpperCamelCase, cx));
+    cx.assert_editor_state(indoc! {"
+        «TheQuickBrown
+        FoxJumpsOver
+        TheLazyDogˇ»
+    "});
+
     // From here on out, test more complex cases of manipulate_text()
 
     // Test no selection case - should affect words cursors are in