keymap: panel menus, toggles and aliases on craft-keymap 6e136c9

- The importer marks Panel Menus items as panel-menu entries.
- Show/Hide commands and the other show-and-hide toggles are marked as
  toggles, so Show and Hide names match only them.
- The Preferences alias names its submenu (Preferences: General…).
- The import test checks an alias match (Exit).
This commit is contained in:
aiongg committed 2026-10-19 04:40:50 +00:00
1 parent 506c429c65
commit 8e20bdfe2d
4 files changed
+36 -13

No files matched your search

Generated
+1 -1
View File
@@ -827,7 +827,7 @@ dependencies = [
[[package]]
name = "craft-keymap"
version = "0.1.0"
source = "git+https://github.com/aiongg/craft-libs?rev=66f22029ba71dad29dcda156f01f680763aa6659#66f22029ba71dad29dcda156f01f680763aa6659"
source = "git+https://github.com/aiongg/craft-libs?rev=6e136c9114d4461e791f0599c4976fc0c01e0048#6e136c9114d4461e791f0599c4976fc0c01e0048"
dependencies = [
"egui",
"serde",
+1 -1
View File
@@ -14,7 +14,7 @@ repository = "https://github.com/storytold/designcraft"
# Shared writer; the immutable revision must be published before this consumer.
craft-pdf = { git = "https://github.com/storytold/craft-libs", rev = "c3487320b2d1de657b860b3c8abb44e1f2b32bd8", version = "=0.1.0", default-features = false }
# Shared keyboard bindings: chords, overrides, conflicts, egui dispatch.
craft-keymap = { git = "https://github.com/aiongg/craft-libs", rev = "66f22029ba71dad29dcda156f01f680763aa6659", version = "=0.1.0", features = ["egui"] }
craft-keymap = { git = "https://github.com/aiongg/craft-libs", rev = "6e136c9114d4461e791f0599c4976fc0c01e0048", version = "=0.1.0", features = ["egui"] }
# internal
designcraft-geom = { path = "crates/geom" }
designcraft-color = { path = "crates/color" }
+7 -1
View File
@@ -36,7 +36,7 @@ const PANEL_KEYS: &[(&str, &str)] = &[
/// Other names shortcut sets use for a command (InDesign's feature names), by command id.
const IMPORT_ALIASES: &[(&str, &str)] = &[
("app.quit", "Exit"),
("app.preferences", "General"),
("app.preferences", "Preferences: General…"),
("app.insertTableDialog", "Insert Table"),
("view.togglePresentation", "Presentation"),
("color.defaultFillStroke", "Apply Default Fill and Stroke Colors"),
@@ -50,6 +50,11 @@ const IMPORT_ALIASES: &[(&str, &str)] = &[
("window.previousDocument", "Previous Window"),
];
/// Commands that show and hide something without "Show/Hide" in their label. A shortcut set may
/// name a toggle by what it does now (`Hide Hidden Characters`); the importer matches such names
/// only to toggles.
const TOGGLES: &[&str] = &["view.hiddenCharacters", "view.tagMarkers"];
/// Extra menu paths for import, where an alias would leave two commands on one name: InDesign's
/// Tools area has Apply Color, which is also `object.color`'s label.
const IMPORT_PATHS: &[(&str, &[&str])] = &[("color.applyColor", &["Tools", "Apply Color"])];
@@ -146,6 +151,7 @@ fn build_catalogue() -> Vec<Bindable> {
continue;
}
let id = b.command.id.as_str();
b.is_toggle = b.label.starts_with("Show/Hide ") || TOGGLES.contains(&id);
b.aliases.extend(IMPORT_ALIASES.iter().filter(|(c, _)| *c == id).map(|(_, a)| a.to_string()));
b.paths.extend(IMPORT_PATHS.iter().filter(|(c, _)| *c == id).map(|(_, p)| p.iter().map(|s| s.to_string()).collect()));
}
+27 -10
View File
@@ -145,20 +145,30 @@ fn strip_suffix_ignore_case<'a>(s: &'a str, suffix: &str) -> Option<&'a str> {
}
/// The set as `craft_keymap::import` reads it. An area named `<menu> Menu` is that menu; the
/// Tools area is the Tools menu, where items named `… Tool` select tools. Items of other areas
/// (panel menus, text and tables, views) have no menu, so they match only by a one-segment name.
/// The keys are read with Mac modifier names when any key in the set uses one.
/// Tools area is the Tools menu, where items named `… Tool` select tools. Items of the Panel Menus
/// area name their panel first (`Character: All Caps`) and match a command under that panel.
/// Items of other areas (text and tables, views) have no menu, so they match only by a one-segment
/// name. The keys are read with Mac modifier names when any key in the set uses one.
fn foreign(set: &ParsedSet) -> ForeignSet {
#[derive(Clone, Copy, Default)]
struct Area<'a> {
menu: Option<&'a str>,
tools: bool,
panel_menu: bool,
}
let flavor = Flavor::detect(set.items.iter().flat_map(|i| &i.entries).map(|e| e.keys.as_str()));
let menus: Vec<(Option<&str>, bool)> = set
let areas: Vec<Area> = set
.areas
.iter()
.map(|a| {
let a = a.trim();
if a.eq_ignore_ascii_case("tools") {
(Some(a), true)
Area { menu: Some(a), tools: true, panel_menu: false }
} else if a.eq_ignore_ascii_case("panel menus") {
Area { panel_menu: true, ..Area::default() }
} else {
(strip_suffix_ignore_case(a, " menu").map(str::trim).filter(|m| !m.is_empty() && !m.contains(':')), false)
let menu = strip_suffix_ignore_case(a, " menu").map(str::trim).filter(|m| !m.is_empty() && !m.contains(':'));
Area { menu, ..Area::default() }
}
})
.collect();
@@ -166,9 +176,12 @@ fn foreign(set: &ParsedSet) -> ForeignSet {
.items
.iter()
.map(|item| {
let (menu, tools) = item.area.and_then(|a| menus.get(a)).copied().unwrap_or((None, false));
let mut entry = ForeignEntry::new(menu, item.name.split(": ").map(str::trim)).at_line(item.line);
entry.is_tool = tools && strip_suffix_ignore_case(&item.name, " tool").is_some();
let area = item.area.and_then(|a| areas.get(a)).copied().unwrap_or_default();
let mut entry = ForeignEntry::new(area.menu, item.name.split(": ").map(str::trim)).at_line(item.line);
if area.panel_menu {
entry = entry.in_panel_menu();
}
entry.is_tool = area.tools && strip_suffix_ignore_case(&item.name, " tool").is_some();
entry.keys = item.entries.iter().map(|e| ForeignKey::read(Some(&e.context), &e.keys, flavor)).collect();
entry
})
@@ -313,6 +326,8 @@ mod tests {
\tColor: Swatches --- Default: Shift+Ctrl+F2\r\n\
Product area : Tools\r\n\
\tPen Tool --- Default: Shift+Ctrl+F3\r\n\
Product area : File Menu\r\n\
\tExit --- Default: Ctrl+Alt+F12\r\n\
garbage line without a separator\r\n";
let r = menus::run_ui(&mut app, "window.importShortcuts", &json!({"text": set})).unwrap().unwrap();
assert_eq!(r["set"], "My Set");
@@ -343,9 +358,11 @@ mod tests {
// A Window menu panel item and a Tools item apply to the panel and the tool.
assert_eq!(crate::keys::shortcut(&app.keymap, &crate::keys::panel("swatches")).as_deref(), Some("Cmd+Shift+F2"));
assert_eq!(crate::keys::shortcut(&app.keymap, &crate::keys::tool("pen")).as_deref(), Some("Cmd+Shift+F3"));
// InDesign's name for a command, as an alias.
assert_eq!(menus::shortcut_of(&app, "app.quit").as_deref(), Some("Cmd+Alt+F12"));
// The numeric keypad key is bound as the main key of the same name, and reported.
assert_eq!(r["approximated"][0]["item"], "File > Close", "{r}");
assert_eq!(r["imported"], 6, "{r}");
assert_eq!(r["imported"], 7, "{r}");
// Reset Shortcuts is the way back.
menus::run_ui(&mut app, "window.resetShortcuts", &json!({})).unwrap().unwrap();
assert_eq!(menus::shortcut_of(&app, "app.palette").as_deref(), Some("Cmd+Enter"));