From fa0a3e9dee444ac375756cfd4c231fbfe7c27c58 Mon Sep 17 00:00:00 2001 From: Harrison Booth <73434116+Harrison-Booth@users.noreply.github.com> Date: Mon, 26 Oct 2026 17:40:21 -0500 Subject: [PATCH] Duplicate: count the names inside groups when numbering copies --- crates/engine/src/cmd/edit.rs | 6 +++++- crates/engine/src/tests.rs | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/cmd/edit.rs b/crates/engine/src/cmd/edit.rs index 3ce31937..8a220c17 100644 --- a/crates/engine/src/cmd/edit.rs +++ b/crates/engine/src/cmd/edit.rs @@ -545,7 +545,11 @@ fn duplicate(s: &mut Session, p: &Value) -> Result { }) .unwrap_or((off, off)); reid("edit.duplicate", doc, &mut copies)?; - let mut taken = super::current_names(doc, sel); + // Every name on the slide, group members included, so a copy never repeats one. + let mut taken = std::collections::HashSet::new(); + deckcraft_model::walk(&list, &mut |sh, _| { + taken.insert(sh.name.clone()); + }); walk_mut(&mut copies, &mut |c| rename_automatic(c, &mut taken)); for (c, b) in copies.iter_mut().zip(boxes) { let mut x = b; diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index f182870f..133e5a46 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -268,6 +268,30 @@ fn duplicate_gives_the_next_automatic_name_and_keeps_a_chosen_one() { assert_eq!(&all[n + 2..], ["Hero", "Hero"], "{all:?}"); } +/// The next automatic name looks at the names inside groups too. +#[test] +fn duplicating_a_group_does_not_repeat_the_names_of_its_members() { + let mut s = session(); + let mut ids = vec![]; + for x in [10, 70, 130, 190] { + s.execute("shape.insert", &json!({"preset": "rect", "rect": [x, 10, 50, 50]})).unwrap(); + ids.push(s.doc().unwrap().selection.shapes[0].0); + } + s.execute("arrange.group", &json!({"ids": [ids[2], ids[3]]})).unwrap(); + let group = s.doc().unwrap().selection.shapes[0].0; + // Fewer top-level shapes than names in use: the next number is one a member already has. + s.execute("edit.delete", &json!({"ids": [ids[0], ids[1]]})).unwrap(); + s.execute("edit.duplicate", &json!({"ids": [group]})).unwrap(); + let doc = s.doc().unwrap(); + let mut all = vec![]; + deckcraft_model::walk(&doc.current_slide().unwrap().shapes, &mut |sh, _| all.push(sh.name.clone())); + let mut unique = all.clone(); + unique.sort(); + unique.dedup(); + assert_eq!(unique.len(), all.len(), "{all:?}"); +} + +/// Group members are renamed like any other copied shape. #[test] fn duplicating_a_group_renames_its_automatic_children() { let mut s = session();