From 07c6b938bced5e38fd62bc38f75ca1dbf52b5f32 Mon Sep 17 00:00:00 2001 From: "Ayberk A." <105879357+AyberkA0@users.noreply.github.com> Date: Thu, 15 Oct 2026 11:18:08 +0300 Subject: [PATCH] Shortcuts: + selects the Add Anchor Point tool (#2142) The tool's default key is "+", and `shortcuts::parse` split a bare "+" as a separator with nothing on either side: the key part came out empty, so the shortcut didn't parse, `tool_for_key` found no tool for a typed "+" and the key did nothing. "-" (Delete Anchor Point) has no separator to trip on, which is why it worked. A bare "+" is now the key itself, the "=" key, as "Cmd++" already was, so "+" typed with Shift on a US layout, by a layout's own "+" key or on the numpad selects the tool. --- crates/ui-egui/src/shortcuts.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/shortcuts.rs b/crates/ui-egui/src/shortcuts.rs index 63fb11ce0..437446f13 100644 --- a/crates/ui-egui/src/shortcuts.rs +++ b/crates/ui-egui/src/shortcuts.rs @@ -15,8 +15,15 @@ pub fn parse(s: &str) -> Option { if s.is_empty() { return None; } - let (mods_part, key_part) = - if let Some(stripped) = s.strip_suffix("++") { (stripped.trim_end_matches('+'), "+") } else { s.rsplit_once('+').unwrap_or(("", s)) }; + // A bare `+` (the Add Anchor Point tool's key) is the key itself, not a separator with + // nothing on either side. + let (mods_part, key_part) = if s == "+" { + ("", "+") + } else if let Some(stripped) = s.strip_suffix("++") { + (stripped.trim_end_matches('+'), "+") + } else { + s.rsplit_once('+').unwrap_or(("", s)) + }; let mut m = Modifiers::NONE; for part in mods_part.split('+').filter(|p| !p.is_empty()) { match part { @@ -975,6 +982,23 @@ mod tests { assert!(zoom(&mut app) < before, "Cmd+- zooms out"); } + /// `+` selects the Add Anchor Point tool, as `-` selects Delete Anchor Point (#2142): typed as + /// Shift+`=` on a US layout, or by a layout's own `+` key or the numpad's. + #[test] + fn plus_selects_the_add_anchor_point_tool() { + assert_eq!(parse("+"), parse("="), "a bare `+` is the `=` key"); + assert_eq!(crate::shortcut_editor::tool_for_key("+"), Some("addAnchor")); + let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default()); + app.session.execute("file.new", &json!({"width": 200, "height": 200})).unwrap(); + for m in [Modifiers::SHIFT, Modifiers::NONE] { + app.select_tool("selection"); + frame(&mut app, vec![egui::Event::ModifiersChanged(m), egui::Event::Text("+".into())]); + assert_eq!(app.session.tool_id(), "addAnchor", "`+` with {m:?}"); + } + frame(&mut app, vec![egui::Event::ModifiersChanged(Modifiers::NONE), egui::Event::Text("-".into())]); + assert_eq!(app.session.tool_id(), "deleteAnchor"); + } + #[test] fn digit_keys_reach_a_dragging_tool_once_per_press() { use vectorcraft_tools::{PointerEvent, PointerKind};