Copy and paste guides: Cut with direct-selected anchors takes the guides too

With anchors and ruler guides selected, Cut deletes the anchors and the
selected guides in one undo step (edit.clear's guides: true reaches the
anchor-deleting path).
This commit is contained in:
Don Omondi
2026-11-04 20:11:59 +07:00
committed by bflatastic
parent 484a78f812
commit 2402f8e1aa
3 changed files with 18 additions and 2 deletions
+1 -1
View File
@@ -713,7 +713,7 @@ fn cut(s: &mut Session, p: &Value) -> Result<Value> {
let ids = selected_roots(s)?;
copy(s, p)?;
// The selected ruler guides it copied go with the objects, in the same undo step (#3226).
if s.doc()?.selection.anchors.is_empty() { clear(s, &json!({ "ids": ids, "guides": true })) } else { clear(s, &json!({})) }
if s.doc()?.selection.anchors.is_empty() { clear(s, &json!({ "ids": ids, "guides": true })) } else { clear(s, &json!({ "guides": true })) }
}
fn clear(s: &mut Session, p: &Value) -> Result<Value> {
+7 -1
View File
@@ -1189,7 +1189,9 @@ fn convert_anchors(s: &mut Session, p: &Value) -> Result<Value> {
ok()
}
pub(crate) fn delete_anchors(s: &mut Session, _: &Value) -> Result<Value> {
pub(crate) fn delete_anchors(s: &mut Session, p: &Value) -> Result<Value> {
// `guides: true` (Cut, #3226): the selected ruler guides go in the same undo step.
let with_guides = p.get("guides").and_then(Value::as_bool).unwrap_or(false);
let st = s.doc()?;
let sel = st.selection.anchors.clone();
let segments = st.selection.segments.clone();
@@ -1197,6 +1199,10 @@ pub(crate) fn delete_anchors(s: &mut Session, _: &Value) -> Result<Value> {
// also catches part of another path must still delete those whole objects.
let whole = st.selection.whole();
s.edit("Clear", |d, selection| {
if with_guides {
let gone = selection.guides.clone();
d.retain_guides(selection, |i, _| !gone.contains(&i));
}
let targets: BTreeSet<NodeId> = whole.into_iter().filter(|id| d.node(*id).is_some_and(|n| !n.is_layer())).collect();
let whole_ids: Vec<NodeId> = targets
.iter()
@@ -74,6 +74,16 @@ fn guides_paste_in_place_onto_another_artboard_and_cut_removes_them() {
assert!(s.doc().unwrap().doc.node(NodeId(rect)).is_none());
assert_eq!(guides(&s).len(), before - 1, "the selected guide goes too");
assert_eq!(s.doc().unwrap().history.undo.len(), undo + 1);
// Cut with direct-selected anchors and a guide: the anchors and the guide go, one undo step.
let path = run(&mut s, "shape.rectangle", json!({"x": 40, "y": 40, "width": 20, "height": 20}))["id"].as_u64().unwrap();
run(&mut s, "guide.add", json!({"vertical": false, "pos": 90}));
let n = guides(&s).len();
run(&mut s, "select.anchors", json!({"id": path, "anchors": [[0, 0]], "mode": "set"}));
run(&mut s, "guide.select", json!({"indexes": [n - 1], "toggle": true}));
let undo = s.doc().unwrap().history.undo.len();
run(&mut s, "edit.cut", json!({}));
assert_eq!(guides(&s).len(), n - 1, "the guide goes with the anchors");
assert_eq!(s.doc().unwrap().history.undo.len(), undo + 1);
// Nothing selected: Copy is off.
run(&mut s, "select.none", json!({}));
assert!(s.execute("edit.copy", &json!({})).is_err());