Clear dangling handles when deleting anchors from a closed path

Found while testing crates/engine/src/cmd/path.rs:632 (without_anchors, closed-path branch uses keep instead of open_run)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-19 22:19:39 +07:00
committed by bflatastic
co-authored by Claude Haiku 5.5
parent bdd5470dcf
commit 85af04a83a
2 changed files with 21 additions and 2 deletions
+1 -2
View File
@@ -602,7 +602,6 @@ fn without_anchors(sp: SubPath, removed: &BTreeSet<usize>) -> Vec<SubPath> {
if gone.is_empty() {
return vec![sp];
}
let keep = |anchors: Vec<Anchor>| (anchors.len() >= 2).then(|| SubPath::new(anchors, false));
let mut runs: Vec<Vec<Anchor>> = vec![];
let mut run = vec![];
for (i, anchor) in sp.anchors.into_iter().enumerate() {
@@ -630,7 +629,7 @@ fn without_anchors(sp: SubPath, removed: &BTreeSet<usize>) -> Vec<SubPath> {
} else if !run.is_empty() {
runs.push(run);
}
runs.into_iter().filter_map(keep).collect()
runs.into_iter().filter_map(open_run).collect()
}
/// Remove connections, splitting open/closed contours into their surviving open runs.
+20
View File
@@ -1968,6 +1968,26 @@ fn open_anchor_delete_preserves_curves_appearance_and_history() {
assert_eq!(s.doc().unwrap().doc, after);
}
#[test]
fn closed_anchor_delete_then_join_closes_with_a_line() {
let mut s = session();
let data = "M100 100C120 60 180 60 200 100C220 140 280 140 300 100C320 60 380 60 400 100C420 140 480 140 500 100C500 200 100 200 100 100Z";
let id = NodeId(s.execute("path.create", &json!({"d": data})).unwrap()["id"].as_u64().unwrap());
s.execute("select.anchors", &json!({"id": id.0, "anchors": [[0, 2]]})).unwrap();
s.execute("path.deleteAnchors", &json!({})).unwrap();
let result = path(&s, id);
assert_eq!(result.subpaths.len(), 1);
let sp = &result.subpaths[0];
assert!(!sp.closed);
assert!(!sp.anchors.first().unwrap().has_in() && !sp.anchors.last().unwrap().has_out(), "dangling handles are cleared");
s.execute("path.join", &json!({"ids": [id.0]})).unwrap();
let joined = path(&s, id);
let sp = &joined.subpaths[0];
assert!(sp.closed);
let closing = sp.segment(sp.segment_count() - 1);
assert!(closing.p1 == closing.p0 && closing.p2 == closing.p3, "closing segment is a line: {closing:?}");
}
#[test]
fn open_anchor_delete_does_not_change_explicit_remove_anchors() {
for command in ["path.removeAnchors", "path.removeAnchor"] {