diff --git a/crates/engine/src/cmd/patternlib.rs b/crates/engine/src/cmd/patternlib.rs index b3e83ff22..3e15c563f 100644 --- a/crates/engine/src/cmd/patternlib.rs +++ b/crates/engine/src/cmd/patternlib.rs @@ -96,7 +96,9 @@ pub(crate) fn import(d: &mut Document, lib: &Document, name: &str) -> String { pub(crate) fn existing_pattern(d: &Document, lib: &Document, name: &str) -> Option { let def = lib.pattern(name)?; let bare = |p: &PatternDef| PatternDef { name: String::new(), art: vec![], ..p.clone() }; - let copy = |n: &str| n == name || n.strip_prefix(name).and_then(|r| r.strip_prefix(' ')).is_some_and(|r| r.parse::().is_ok()); + let copy = |n: &str| { + n == name || n.strip_prefix(name).and_then(|r| r.strip_prefix(' ')).is_some_and(|r| !r.is_empty() && r.bytes().all(|b| b.is_ascii_digit())) + }; let mut found: Vec<&PatternDef> = d.patterns.iter().filter(|p| copy(&p.name) && bare(p) == bare(def) && p.art == def.art).collect(); found.sort_by_key(|p| p.name != name); found.first().map(|p| p.name.clone()) @@ -150,3 +152,19 @@ fn geometric_patterns(d: &mut Document) { add(d, "Crosses", 10.0, 10.0, TileType::Grid, vec![rect(4.0, 1.5, 6.0, 8.5), rect(1.5, 4.0, 8.5, 6.0)]); add(d, "Zigzag", 10.0, 8.0, TileType::Grid, vec![polygon(&[(0.0, 5.0), (5.0, 1.0), (10.0, 5.0), (10.0, 7.0), (5.0, 3.0), (0.0, 7.0)])]); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn plus_signed_suffix_is_not_a_copy_number() { + let mut lib = Document::new(100.0, 100.0); + lib.patterns.push(PatternDef::new("Dots", vec![])); + for (other, expected) in [("Dots +2", None), ("Dots -2", None), ("Dots 2a", None), ("Dots ", None), ("Dots 2", Some("Dots 2"))] { + let mut d = Document::new(100.0, 100.0); + d.patterns.push(PatternDef::new(other, vec![])); + assert_eq!(existing_pattern(&d, &lib, "Dots").as_deref(), expected, "{other}"); + } + } +}