From 8fd6ec124ba8a3b9058833bd384bd2162bca0e43 Mon Sep 17 00:00:00 2001 From: prxnvt <53838599+prxnvt@users.noreply.github.com> Date: Sun, 25 Oct 2026 04:32:53 -0400 Subject: [PATCH] Engine: a macro shortcut is one letter, alone or after Ctrl+Shift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `parse_shortcut` took the last letter of any spelling, so `"Ctrl+Alt+M"` was saved as Ctrl+Shift+M. It now takes a bare letter or one after Ctrl+Shift, Cmd+Shift or ⌘⇧, and refuses other modifiers. - Test: `shortcuts_parse_to_one_letter_and_avoid_reserved_and_taken_ones`. --- crates/engine/src/macros/mod.rs | 20 ++++++++++++-------- crates/engine/src/tests/macros.rs | 4 +++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/crates/engine/src/macros/mod.rs b/crates/engine/src/macros/mod.rs index f500b9815..ecbe6f674 100644 --- a/crates/engine/src/macros/mod.rs +++ b/crates/engine/src/macros/mod.rs @@ -435,15 +435,19 @@ pub const RESERVED_SHORTCUTS: &[(char, &str)] = &[ ('Z', "Redo"), ]; -/// The letter of a macro shortcut: `"Ctrl+Shift+M"`, `"⌘⇧M"` and `"m"` all give `'M'`. `None` -/// when it is not one letter from A to Z. +/// The letter of a macro shortcut: `"Ctrl+Shift+M"`, `"Cmd+Shift+M"`, `"⌘⇧M"` and `"m"` all give +/// `'M'`. `None` when it is not one letter from A to Z, alone or after Ctrl+Shift (Cmd+Shift): +/// other modifiers (`"Ctrl+Alt+M"`) are refused rather than read as Ctrl+Shift. pub fn parse_shortcut(s: &str) -> Option { - let last = s.trim().rsplit(['+', '⇧', '⌘']).next()?.trim(); - let mut chars = last.chars(); - match (chars.next(), chars.next()) { - (Some(c), None) if c.is_ascii_alphabetic() => Some(c.to_ascii_uppercase()), - _ => None, - } + let letter = |t: &str| { + let mut chars = t.trim().chars(); + match (chars.next(), chars.next()) { + (Some(c), None) if c.is_ascii_alphabetic() => Some(c.to_ascii_uppercase()), + _ => None, + } + }; + let t = s.trim().to_ascii_lowercase(); + ["ctrl+shift+", "cmd+shift+", "⌘⇧"].iter().find_map(|p| t.strip_prefix(p)).map_or_else(|| letter(&t), letter) } /// How a shortcut is stored and shown: `Ctrl+Shift+M`. diff --git a/crates/engine/src/tests/macros.rs b/crates/engine/src/tests/macros.rs index 19a23a1ac..2903ac79a 100644 --- a/crates/engine/src/tests/macros.rs +++ b/crates/engine/src/tests/macros.rs @@ -2400,7 +2400,9 @@ fn shortcuts_parse_to_one_letter_and_avoid_reserved_and_taken_ones() { assert_eq!(parse_shortcut("Ctrl+Shift+M"), Some('M')); assert_eq!(parse_shortcut("⌘⇧k"), Some('K')); assert_eq!(parse_shortcut(" q "), Some('Q')); - for bad in ["Ctrl+Shift+F5", "Ctrl+Shift+", "", "Ctrl+Shift+é"] { + assert_eq!(parse_shortcut("cmd+shift+r"), Some('R')); + // Other modifiers are refused, not read as Ctrl+Shift. + for bad in ["Ctrl+Shift+F5", "Ctrl+Shift+", "", "Ctrl+Shift+é", "Ctrl+Alt+M", "Shift+M", "Alt+M", "Ctrl+M"] { assert_eq!(parse_shortcut(bad), None, "{bad}"); } assert_eq!(shortcut_text('m'), "Ctrl+Shift+M");