From 305d6e9c89c89037ae4ef0835c4b1dcc9a134584 Mon Sep 17 00:00:00 2001
From: Michael Davis <mcarsondavis@gmail.com>
Date: Mon, 8 Jan 2024 20:04:34 -0500
Subject: [PATCH] Normalize `S-<lower-ascii>` keymaps to uppercase ascii
 (#9213)

---
 helix-view/src/input.rs | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs
index 0f4ffaac..5f5067ea 100644
--- a/helix-view/src/input.rs
+++ b/helix-view/src/input.rs
@@ -325,7 +325,7 @@ impl std::str::FromStr for KeyEvent {
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         let mut tokens: Vec<_> = s.split('-').collect();
-        let code = match tokens.pop().ok_or_else(|| anyhow!("Missing key code"))? {
+        let mut code = match tokens.pop().ok_or_else(|| anyhow!("Missing key code"))? {
             keys::BACKSPACE => KeyCode::Backspace,
             keys::ENTER => KeyCode::Enter,
             keys::LEFT => KeyCode::Left,
@@ -405,6 +405,18 @@ impl std::str::FromStr for KeyEvent {
             modifiers.insert(flag);
         }
 
+        // Normalize character keys so that characters like C-S-r and C-R
+        // are represented by equal KeyEvents.
+        match code {
+            KeyCode::Char(ch)
+                if ch.is_ascii_lowercase() && modifiers.contains(KeyModifiers::SHIFT) =>
+            {
+                code = KeyCode::Char(ch.to_ascii_uppercase());
+                modifiers.remove(KeyModifiers::SHIFT);
+            }
+            _ => (),
+        }
+
         Ok(KeyEvent { code, modifiers })
     }
 }
@@ -684,6 +696,19 @@ mod test {
                 modifiers: KeyModifiers::ALT | KeyModifiers::CONTROL
             }
         );
+
+        assert_eq!(
+            str::parse::<KeyEvent>("C-S-r").unwrap(),
+            str::parse::<KeyEvent>("C-R").unwrap(),
+        );
+
+        assert_eq!(
+            str::parse::<KeyEvent>("S-w").unwrap(),
+            KeyEvent {
+                code: KeyCode::Char('W'),
+                modifiers: KeyModifiers::NONE
+            }
+        );
     }
 
     #[test]