Engine: a macro shortcut is one letter, alone or after Ctrl+Shift

`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`.
This commit is contained in:
prxnvt
2026-10-25 06:48:57 -04:00
parent ffacf7405f
commit 8fd6ec124b
2 changed files with 15 additions and 9 deletions
+12 -8
View File
@@ -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<char> {
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`.
+3 -1
View File
@@ -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");