From 636fc8b8504555cab7354deb8d062fa6fc88d61d Mon Sep 17 00:00:00 2001 From: aiongg Date: Tue, 20 Oct 2026 20:59:43 +0000 Subject: [PATCH] keymap: import-only paths on Bindable Bindable::import_paths (with_import_path) are read by import matching like menu paths, and make no areas or groups in the dialog, so a tool's ["Tools", label] path no longer shows a Tools Menu entry. --- crates/keymap/README.md | 4 +++- crates/keymap/src/import.rs | 10 +++++++--- crates/keymap/src/keymap.rs | 11 +++++++++++ crates/keymap/src/ui/rows.rs | 15 +++++++++++++++ crates/keymap/tests/import.rs | 14 ++++++++++++++ 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/crates/keymap/README.md b/crates/keymap/README.md index 472c2883..b9291572 100644 --- a/crates/keymap/README.md +++ b/crates/keymap/README.md @@ -242,7 +242,9 @@ assert_eq!((report.unmatched[0].item.as_str(), report.unmatched[0].line), ("File it `in_panel_menu()`. Tool entries match only tools. - Names are compared after `import::normalize_label`: case, `…`, `...`, `&`, colons and extra spaces aside, so the alias `Preferences: General…` matches `Edit > Preferences > General...`. - Aliases (`Bindable::with_alias`) count wherever labels do. + Aliases (`Bindable::with_alias`) count wherever labels do, and import paths + (`Bindable::with_import_path`, such as `["Tools", label]` for a tool) wherever menu paths do; + the dialog makes no areas or groups from import paths. - Panel menus: sources list panel-menu items with the panel's name in front (InDesign's Panel Menus area writes `Character: All Caps`; Illustrator and Photoshop sets have similar areas). The reader splits the name into segments and marks the entry `ForeignEntry::in_panel_menu()`. diff --git a/crates/keymap/src/import.rs b/crates/keymap/src/import.rs index a387ad67..5277c9c8 100644 --- a/crates/keymap/src/import.rs +++ b/crates/keymap/src/import.rs @@ -860,7 +860,7 @@ impl Names { for name in &names { add(&mut self.anywhere, name.clone(), i); } - for path in &b.paths { + for path in b.paths.iter().chain(&b.import_paths) { let mut segs: Vec = path.iter().map(|s| normalize_label(s)).collect(); if let [_, .., last] = segs.as_mut_slice() { *last = form(last); @@ -936,7 +936,7 @@ impl Index { ix.tool.push(matches!(b.kind, Kind::Tool { .. })); ix.keys.insert(b.command.key(), i); ix.names.add(i, b, str::to_string); - ix.segments.extend(b.paths.iter().flatten().map(|s| normalize_label(s))); + ix.segments.extend(b.paths.iter().chain(&b.import_paths).flatten().map(|s| normalize_label(s))); if b.is_toggle { ix.toggles.add(i, b, toggle_name); } @@ -1000,7 +1000,11 @@ fn suggest(keymap: &Keymap, entries: &[ToSuggest]) -> Vec { let candidates: Vec = pool .iter() .map(|b| { - let labels = std::iter::once(&b.label).chain(&b.aliases).chain(b.paths.iter().filter_map(|p| p.last())).cloned().collect(); + let labels = std::iter::once(&b.label) + .chain(&b.aliases) + .chain(b.paths.iter().chain(&b.import_paths).filter_map(|p| p.last())) + .cloned() + .collect(); namematch::Candidate { id: b.command.id.clone(), labels } }) .collect(); diff --git a/crates/keymap/src/keymap.rs b/crates/keymap/src/keymap.rs index 8dc9fd94..8c026945 100644 --- a/crates/keymap/src/keymap.rs +++ b/crates/keymap/src/keymap.rs @@ -141,6 +141,10 @@ pub struct Bindable { /// Menu paths, the main one first; used by search and import. #[serde(default)] pub paths: Vec>, + /// Paths only import matching reads: where foreign sets file the command and the app's menus + /// do not, such as `["Tools", label]` for a tool. They make no areas or groups in the dialog. + #[serde(default)] + pub import_paths: Vec>, /// Other names: labels in other UI languages, older names. #[serde(default)] pub aliases: Vec, @@ -163,6 +167,7 @@ impl Bindable { command: command.into(), label: label.into(), paths: Vec::new(), + import_paths: Vec::new(), aliases: Vec::new(), scope, kind: Kind::Command, @@ -192,6 +197,12 @@ impl Bindable { self } + /// Adds a path only import matching reads ([`Bindable::import_paths`]). + pub fn with_import_path(mut self, path: Vec) -> Bindable { + self.import_paths.push(path); + self + } + pub fn with_alias(mut self, alias: impl Into) -> Bindable { self.aliases.push(alias.into()); self diff --git a/crates/keymap/src/ui/rows.rs b/crates/keymap/src/ui/rows.rs index 11825af0..6b17b67f 100644 --- a/crates/keymap/src/ui/rows.rs +++ b/crates/keymap/src/ui/rows.rs @@ -607,6 +607,21 @@ pub(crate) mod tests { Ok(()) } + #[test] + fn import_paths_make_no_areas_or_groups() { + let tool = |id: &str, label: &str| { + Bindable::new(id, label, Scope::app()) + .with_kind(Kind::Tool { group: None }) + .with_import_path(vec!["Tools".into(), label.into()]) + .with_default(key("P")) + }; + let km = Keymap::new(vec![tool("tool.pen", "Pen Tool")], Scopes::new(), Platform::Mac); + let o = Options::default(); + let names: Vec = areas(&km, &o, &English).into_iter().map(|a| a.label).collect(); + assert_eq!(names, ["All Commands", "Tools"]); + assert_eq!(lines(&km, &o, &English, "", AreaId::All, Filter::All), ["# Tools", "Pen Tool: P"]); + } + #[test] fn hidden_entries_are_not_listed_but_still_conflict() -> Result<(), crate::AssignError> { let mut km = fixture(Platform::Mac); diff --git a/crates/keymap/tests/import.rs b/crates/keymap/tests/import.rs index dd66bcb6..77346e14 100644 --- a/crates/keymap/tests/import.rs +++ b/crates/keymap/tests/import.rs @@ -676,6 +676,20 @@ fn aliases_match_like_labels() { assert!(r.unmatched.is_empty(), "{:?}", r.unmatched); } +#[test] +fn import_paths_match_like_menu_paths() { + let catalog = vec![ + command("object.color", "Apply Color", &["Object", "Apply Color"], &[]), + command("color.applyColor", "Apply Color", &[], &[]).with_import_path(vec!["Tools".into(), "Apply Color".into()]), + ]; + let d = "Default"; + let entries = vec![win("Tools", &["Apply Color"], &[(d, "Ctrl+,")])]; + let (km, r) = import_into(catalog, entries, &default_context()); + has(&km, "color.applyColor", &["Cmd+,"]); + has(&km, "object.color", &[]); + assert!(r.unmatched.is_empty(), "{:?}", r.unmatched); +} + #[test] fn show_and_hide_are_read_off_only_for_toggles() { let catalog = vec![