From 722cfedb382abf2a4e48ac45bdfd9b3c5de50a58 Mon Sep 17 00:00:00 2001
From: Cor Peters <luctius@users.noreply.github.com>
Date: Fri, 16 Jul 2021 18:12:59 +0200
Subject: [PATCH] Added change_case command (#441)

* Added change_case command

* Added switch_to_uppercase and switch_to_lowercase

Renamed change_case to switch_case.

* Updated the Keymap section of the Book

* Use flat_map instead of map + flatten

* Fix switch_to_uppercase using to_lowercase

* Switched 'Alt-`' to uppercase and '`' to lowercase

Co-authored-by: Cor <prive@corpeters.nl>
---
 book/src/keymap.md         | 43 ++++++++++++++++--------------
 helix-term/src/commands.rs | 54 ++++++++++++++++++++++++++++++++++++++
 helix-term/src/keymap.rs   |  4 +++
 3 files changed, 81 insertions(+), 20 deletions(-)

diff --git a/book/src/keymap.md b/book/src/keymap.md
index c0c455d3..5d6e5795 100644
--- a/book/src/keymap.md
+++ b/book/src/keymap.md
@@ -41,26 +41,29 @@
 
 ### Changes
 
-| Key   | Description                                     |
-| ----- | -----------                                     |
-| `r`   | Replace with a character                        |
-| `R`   | Replace with yanked text                        |
-| `i`   | Insert before selection                         |
-| `a`   | Insert after selection (append)                 |
-| `I`   | Insert at the start of the line                 |
-| `A`   | Insert at the end of the line                   |
-| `o`   | Open new line below selection                   |
-| `o`   | Open new line above selection                   |
-| `u`   | Undo change                                     |
-| `U`   | Redo change                                     |
-| `y`   | Yank selection                                  |
-| `p`   | Paste after selection                           |
-| `P`   | Paste before selection                          |
-| `>`   | Indent selection                                |
-| `<`   | Unindent selection                              |
-| `=`   | Format selection                                |
-| `d`   | Delete selection                                |
-| `c`   | Change selection (delete and enter insert mode) |
+| Key      | Description                                     |
+| -----    | -----------                                     |
+| `r`      | Replace with a character                        |
+| `R`      | Replace with yanked text                        |
+| `~`      | Switch case of the selected text                |
+| `\``     | Set the selected text to upper case             |
+| `Alt-\`` | Set the selected text to lower case             |
+| `i`      | Insert before selection                         |
+| `a`      | Insert after selection (append)                 |
+| `I`      | Insert at the start of the line                 |
+| `A`      | Insert at the end of the line                   |
+| `o`      | Open new line below selection                   |
+| `o`      | Open new line above selection                   |
+| `u`      | Undo change                                     |
+| `U`      | Redo change                                     |
+| `y`      | Yank selection                                  |
+| `p`      | Paste after selection                           |
+| `P`      | Paste before selection                          |
+| `>`      | Indent selection                                |
+| `<`      | Unindent selection                              |
+| `=`      | Format selection                                |
+| `d`      | Delete selection                                |
+| `c`      | Change selection (delete and enter insert mode) |
 
 ### Selection manipulation
 
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 3b208ca8..7e769f4e 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -186,6 +186,9 @@ impl Command {
         extend_till_prev_char,
         extend_prev_char,
         replace,
+        switch_case,
+        switch_to_uppercase,
+        switch_to_lowercase,
         page_up,
         page_down,
         half_page_up,
@@ -780,6 +783,57 @@ fn replace(cx: &mut Context) {
     })
 }
 
+fn switch_case(cx: &mut Context) {
+    let (view, doc) = current!(cx.editor);
+    let transaction =
+        Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
+            let text: Tendril = range
+                .fragment(doc.text().slice(..))
+                .chars()
+                .flat_map(|ch| {
+                    if ch.is_lowercase() {
+                        ch.to_uppercase().collect()
+                    } else if ch.is_uppercase() {
+                        ch.to_lowercase().collect()
+                    } else {
+                        vec![ch]
+                    }
+                })
+                .collect();
+
+            (range.from(), range.to() + 1, Some(text))
+        });
+
+    doc.apply(&transaction, view.id);
+    doc.append_changes_to_history(view.id);
+}
+
+fn switch_to_uppercase(cx: &mut Context) {
+    let (view, doc) = current!(cx.editor);
+    let transaction =
+        Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
+            let text: Tendril = range.fragment(doc.text().slice(..)).to_uppercase().into();
+
+            (range.from(), range.to() + 1, Some(text))
+        });
+
+    doc.apply(&transaction, view.id);
+    doc.append_changes_to_history(view.id);
+}
+
+fn switch_to_lowercase(cx: &mut Context) {
+    let (view, doc) = current!(cx.editor);
+    let transaction =
+        Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
+            let text: Tendril = range.fragment(doc.text().slice(..)).to_lowercase().into();
+
+            (range.from(), range.to() + 1, Some(text))
+        });
+
+    doc.apply(&transaction, view.id);
+    doc.append_changes_to_history(view.id);
+}
+
 fn scroll(cx: &mut Context, offset: usize, direction: Direction) {
     use Direction::*;
     let (view, doc) = current!(cx.editor);
diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs
index fe32e49f..32994c37 100644
--- a/helix-term/src/keymap.rs
+++ b/helix-term/src/keymap.rs
@@ -82,6 +82,10 @@ impl Default for Keymaps {
             key!('r') => Command::replace,
             key!('R') => Command::replace_with_yanked,
 
+            key!('~') => Command::switch_case,
+            alt!('`') => Command::switch_to_uppercase,
+            key!('`') => Command::switch_to_lowercase,
+
             key!(Home) => Command::goto_line_start,
             key!(End) => Command::goto_line_end,