mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-14 19:26:59 -04:00
fix(shortcuts): Clear and reassign also drop a command's panel copy of its key (part of #1333)
This commit is contained in:
1 parent
0879bd7a7e
commit
528e525d67
2 files changed
+56
-2
No files matched your search
@@ -737,7 +737,8 @@ impl Shortcuts {
|
||||
let nb = Binding { command: command.into(), keys: chord.canonical(), panel: panel.map(str::to_string) };
|
||||
let before = self.snapshot();
|
||||
if !add {
|
||||
self.bindings.retain(|b| !(same_shortcut_command(&b.command, command) && b.context() == nb.context()));
|
||||
let copies = if nb.panel.is_none() { self.app_chords(command, None) } else { Vec::new() };
|
||||
self.bindings.retain(|b| !(same_shortcut_command(&b.command, command) && (b.context() == nb.context() || is_copy(b, &copies))));
|
||||
}
|
||||
let mut reassigned = Vec::new();
|
||||
if !keep_conflicts {
|
||||
@@ -769,6 +770,7 @@ impl Shortcuts {
|
||||
let before = self.snapshot();
|
||||
let n0 = self.bindings.len();
|
||||
let twins = shortcut_twins(command);
|
||||
let copies = if panel == Some(None) { self.app_chords(command, chord.as_ref()) } else { Vec::new() };
|
||||
self.bindings.retain(|b| {
|
||||
let cmd = same_shortcut_command(&b.command, command);
|
||||
let key_ok = chord.as_ref().is_none_or(|c| b.chord().as_ref() == Some(c));
|
||||
@@ -778,7 +780,7 @@ impl Shortcuts {
|
||||
let panel_ok = match &panel {
|
||||
None => true,
|
||||
Some(p) if p.is_none() && twins => true,
|
||||
Some(p) => &b.panel == p,
|
||||
Some(p) => &b.panel == p || is_copy(b, &copies),
|
||||
};
|
||||
!(cmd && key_ok && panel_ok)
|
||||
});
|
||||
@@ -916,6 +918,16 @@ impl Shortcuts {
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
/// The application-wide keys of `command` (only `key`, when given).
|
||||
fn app_chords(&self, command: &str, key: Option<&Chord>) -> Vec<Chord> {
|
||||
self.bindings
|
||||
.iter()
|
||||
.filter(|b| same_shortcut_command(&b.command, command) && b.panel.is_none())
|
||||
.filter_map(Binding::chord)
|
||||
.filter(|c| key.is_none_or(|k| k == c))
|
||||
.collect()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- queries
|
||||
|
||||
pub fn for_command(&self, id: &str) -> Vec<&Binding> {
|
||||
@@ -1017,6 +1029,12 @@ fn same_shortcut_command(bound: &str, target: &str) -> bool {
|
||||
bound == target || (shortcut_twins(bound) && shortcut_twins(target))
|
||||
}
|
||||
|
||||
/// A panel binding on one of the command's application keys (New Bin's Cmd+B in the Project
|
||||
/// panel) is a copy of that shortcut, so editing the application shortcut edits it too (#1333).
|
||||
fn is_copy(b: &Binding, app_chords: &[Chord]) -> bool {
|
||||
b.panel.is_some() && b.chord().is_some_and(|c| app_chords.contains(&c))
|
||||
}
|
||||
|
||||
fn check_panel(panel: Option<&str>) -> std::result::Result<Option<&'static str>, String> {
|
||||
match panel {
|
||||
None => Ok(None),
|
||||
|
||||
@@ -133,6 +133,42 @@ fn clear_close_sequence_also_clears_file_close() {
|
||||
assert_eq!(s.shortcuts.resolve(&w, None, Platform::current()).unwrap().command, "sequence.addEdit");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clear_new_bin_frees_cmd_b_in_the_project_panel_too() {
|
||||
// #1333: New Bin has Cmd+B application-wide and again in the Project panel. The editor's Clear
|
||||
// sends panel Application, so only the first went; the Project panel kept Cmd+B.
|
||||
let dir = temp_dir("new-bin");
|
||||
let mut s = Session::default();
|
||||
s.shortcuts.set_dir(&dir);
|
||||
let b = Chord::parse("Cmd+B").unwrap();
|
||||
let p = Platform::current();
|
||||
assert_eq!(s.shortcuts.resolve(&b, Some("Project"), p).unwrap().command, "file.newBin");
|
||||
s.execute("shortcuts.clear", json!({"command": "file.newBin", "panel": "Application"})).unwrap();
|
||||
assert!(s.shortcuts.for_command("file.newBin").is_empty(), "{:?}", s.shortcuts.for_command("file.newBin"));
|
||||
s.execute("shortcuts.set", json!({"command": "sequence.addEdit", "keys": "Cmd+B"})).unwrap();
|
||||
let mut t = Shortcuts::new();
|
||||
t.set_dir(&dir);
|
||||
for sc in [&s.shortcuts, &t] {
|
||||
assert_eq!(sc.resolve(&b, None, p).unwrap().command, "sequence.addEdit");
|
||||
assert_eq!(sc.resolve(&b, Some("Project"), p).unwrap().command, "sequence.addEdit");
|
||||
assert!(sc.for_command("file.newBin").is_empty());
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reassigning_new_bin_moves_its_project_panel_key_too() {
|
||||
// #1333: assigning New Bin another key replaced Cmd+B application-wide only.
|
||||
let mut s = Session::default();
|
||||
s.execute("shortcuts.set", json!({"command": "file.newBin", "keys": "Cmd+Alt+B"})).unwrap();
|
||||
let keys: Vec<(&str, Option<&str>)> = s.shortcuts.for_command("file.newBin").iter().map(|b| (b.keys.as_str(), b.panel.as_deref())).collect();
|
||||
assert_eq!(keys, [("Cmd+Alt+B", None)]);
|
||||
assert!(s.shortcuts.resolve(&Chord::parse("Cmd+B").unwrap(), Some("Project"), Platform::Mac).is_none());
|
||||
// a panel key of its own (History ▸ Left for Undo) is not a copy of the application one: it stays
|
||||
s.execute("shortcuts.set", json!({"command": "edit.undo", "keys": "Cmd+Alt+Z"})).unwrap();
|
||||
assert!(s.shortcuts.for_command("edit.undo").iter().any(|b| b.panel.as_deref() == Some("History") && b.keys == "Left"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn panel_shortcuts_override_application_ones_with_focus() {
|
||||
let s = Session::default();
|
||||
|
||||
Reference in new issue
Block a user