G11: Preserve gaps when deleting open-path anchors

Keep surviving drawable runs separate when Delete or Backspace removes an open-path anchor. Preserve appearance, selection and one-step Undo.

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
sanyamsingh001
2026-10-16 04:44:58 +07:00
committed by bflatastic
co-authored by Codex
parent a1b3c4804f
commit 67f9d134ed
8 changed files with 270 additions and 16 deletions
+9 -9
View File
@@ -565,8 +565,8 @@ pub(crate) fn delete_anchors(s: &mut Session, _: &Value) -> Result<Value> {
})
.collect();
} else {
// Remove every selected anchor against the original indexes. A closed path opens
// across each deleted run and keeps the surviving stretches in their old order.
// Remove every selected anchor against the original indexes, keeping surviving
// stretches separate rather than joining across deleted anchors.
path.subpaths = std::mem::take(&mut path.subpaths)
.into_iter()
.enumerate()
@@ -593,9 +593,8 @@ pub(crate) fn delete_anchors(s: &mut Session, _: &Value) -> Result<Value> {
ok()
}
/// Remove anchors `removed`. An open path stays one path and joins across the gap. A closed path
/// opens there: each stretch of anchors that were not deleted becomes its own open path, in the
/// original order, including a stretch that wraps past the last anchor.
/// Remove anchors and their incident segments, keeping each surviving stretch as an open path.
/// Only a closed path can have a surviving stretch that wraps past the last anchor.
fn without_anchors(sp: SubPath, removed: &BTreeSet<usize>) -> Vec<SubPath> {
let n = sp.anchors.len();
let gone: BTreeSet<usize> = removed.iter().copied().filter(|&i| i < n).collect();
@@ -603,9 +602,6 @@ fn without_anchors(sp: SubPath, removed: &BTreeSet<usize>) -> Vec<SubPath> {
return vec![sp];
}
let keep = |anchors: Vec<Anchor>| (anchors.len() >= 2).then(|| SubPath::new(anchors, false));
if !sp.closed {
return keep(sp.anchors.into_iter().enumerate().filter(|(i, _)| !gone.contains(i)).map(|(_, a)| a).collect()).into_iter().collect();
}
let mut runs: Vec<Vec<Anchor>> = vec![];
let mut run = vec![];
for (i, anchor) in sp.anchors.into_iter().enumerate() {
@@ -617,7 +613,11 @@ fn without_anchors(sp: SubPath, removed: &BTreeSet<usize>) -> Vec<SubPath> {
run.push(anchor);
}
}
// The anchors before the first deletion and after the last are one stretch.
if !sp.closed {
runs.push(run);
return runs.into_iter().filter_map(open_run).collect();
}
// The anchors before the first deletion and after the last are one closed-path stretch.
if gone.contains(&0) {
if !run.is_empty() {
runs.push(run);