Fix #903: Reselect repeats a Same command after Deselect
Select › Reselect repeated the last selection command, but a Select Same command needs a selected object to compare with, so after Deselect it failed with "nothing selected". Reselect now remembers the objects that were selected when the command ran and, with nothing selected, takes the reference from those still in the document. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ba2fc64d89
commit
6917984329
|
|
@ -246,8 +246,9 @@ fn candidates(s: &Session, f: impl Fn(&Node) -> bool) -> Result<Vec<NodeId>> {
|
|||
|
||||
fn finish_same(s: &mut Session, cmd: &str, ids: Vec<NodeId>) -> Result<Value> {
|
||||
let n = ids.len();
|
||||
let from = s.doc()?.selection.objects.clone();
|
||||
s.select(|_, sel| sel.set(ids))?;
|
||||
s.doc_mut()?.last_selection_cmd = Some((cmd.to_string(), json!({})));
|
||||
s.doc_mut()?.last_selection_cmd = Some((cmd.to_string(), json!({}), from));
|
||||
Ok(json!({ "count": n }))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -216,8 +216,20 @@ fn none(s: &mut Session, _: &Value) -> Result<Value> {
|
|||
}
|
||||
|
||||
fn reselect(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
let Some((c, p)) = s.doc()?.last_selection_cmd.clone() else { return ok() };
|
||||
s.execute(&c, &p)
|
||||
let st = s.doc()?;
|
||||
let Some((c, p, from)) = st.last_selection_cmd.clone() else { return ok() };
|
||||
// After Deselect, a Same command takes its reference again from the objects that were selected
|
||||
// when it ran, those still there (#903).
|
||||
let from: Vec<NodeId> = from.into_iter().filter(|id| st.doc.node(*id).is_some()).collect();
|
||||
let restore = st.selection.objects.is_empty() && !from.is_empty();
|
||||
if restore {
|
||||
s.select(|_, sel| sel.set(from))?;
|
||||
}
|
||||
let r = s.execute(&c, &p);
|
||||
if restore && r.is_err() {
|
||||
s.select(|_, sel| sel.clear())?;
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
fn inverse(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
|
|
@ -401,8 +413,9 @@ fn select_where(s: &mut Session, cmd: &str, p: &Value, f: impl Fn(&Document, &No
|
|||
for l in st.doc.layers.iter().filter(|l| l.visible && !l.locked) {
|
||||
visit(&st.doc, l, &f, &mut ids);
|
||||
}
|
||||
let from = st.selection.objects.clone();
|
||||
s.select(|_, sel| sel.set(ids.iter().copied()))?;
|
||||
s.doc_mut()?.last_selection_cmd = Some((cmd.to_string(), p.clone()));
|
||||
s.doc_mut()?.last_selection_cmd = Some((cmd.to_string(), p.clone(), from));
|
||||
Ok(json!({ "count": ids.len() }))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,8 +126,9 @@ pub struct DocState {
|
|||
pub undo_group: Option<UndoGroup>,
|
||||
/// For Object → Transform → Transform Again (⌘D).
|
||||
pub last_transform: Option<(Affine, bool)>,
|
||||
/// Selection saved by Select → Reselect.
|
||||
pub last_selection_cmd: Option<(String, Value)>,
|
||||
/// What Select → Reselect repeats: the last selection command, its params and the objects
|
||||
/// selected when it ran (a Same command's reference objects).
|
||||
pub last_selection_cmd: Option<(String, Value, Vec<NodeId>)>,
|
||||
/// Process-unique id of this open document (tab indices shift when tabs close).
|
||||
pub uid: u64,
|
||||
/// View Opacity Mask (Alt-click the mask thumbnail): the masked object whose mask the canvas
|
||||
|
|
|
|||
|
|
@ -149,6 +149,18 @@ fn select_same_fill() {
|
|||
let r = s.execute("select.same.fillColor", &json!({})).unwrap();
|
||||
assert_eq!(r["count"], 2);
|
||||
assert!(!s.doc().unwrap().selection.contains(a));
|
||||
// Reselect after Deselect repeats it from the same reference object (#903).
|
||||
let blue = s.doc().unwrap().selection.objects.clone();
|
||||
s.execute("select.none", &json!({})).unwrap();
|
||||
s.execute("select.reselect", &json!({})).unwrap();
|
||||
assert_eq!(s.doc().unwrap().selection.objects, blue);
|
||||
// With its reference object gone, it fails as Select Same does, and selects nothing.
|
||||
s.execute("select.none", &json!({})).unwrap();
|
||||
for id in &blue {
|
||||
s.execute("edit.clear", &json!({"ids": [id.0]})).unwrap();
|
||||
}
|
||||
assert!(s.execute("select.reselect", &json!({})).is_err());
|
||||
assert!(s.doc().unwrap().selection.objects.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in New Issue