mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-26 18:56:55 -06:00
Merge pull request #4243 from dotCooCoo/fix/undo-scope-cancel-forgets-cut-journal-entries
Undo: a canceled undo scope drops the journal entries it cut from open undo groups
This commit is contained in:
@@ -2520,7 +2520,7 @@ impl Session {
|
||||
/// closes it. A scope that joined an open group leaves the group open; with `cancel`, it puts the
|
||||
/// document and its selection back as they were when the scope began and cuts the journal back to
|
||||
/// where the scope began (only while the group's step is still the newest one), and an undo step
|
||||
/// that the scope's first edit recorded goes too.
|
||||
/// that the scope's first edit recorded goes too. The open undo groups drop the cut entries.
|
||||
pub fn end_undo_scope(&mut self, scope: UndoScope, cancel: bool) {
|
||||
let Some((doc, selection, first)) = scope.joined else {
|
||||
self.end_document_undo_group(scope.uid, cancel);
|
||||
@@ -2549,6 +2549,11 @@ impl Session {
|
||||
st.history.recost_last(&st.doc);
|
||||
st.revision += 1;
|
||||
self.journal.truncate(scope.journal);
|
||||
// The next commands take the cut entries' numbers, so no open undo group keeps them.
|
||||
for g in self.docs.iter_mut().filter_map(|st| st.undo_group.as_mut()) {
|
||||
g.journal.retain(|&(n, _)| n < scope.journal);
|
||||
g.steps.retain(|&(n, _)| n < scope.journal);
|
||||
}
|
||||
}
|
||||
|
||||
/// Commands with enablement (for menus, palette, MCP `list_commands`).
|
||||
|
||||
@@ -780,6 +780,34 @@ fn an_undo_scope_in_an_open_group_takes_back_only_its_own_edits() {
|
||||
assert_eq!(objects(&s), 0, "one undo takes back the group's edits");
|
||||
}
|
||||
|
||||
/// A canceled undo scope that joined an open group forgets the journal entries it cut: when a command
|
||||
/// in another document takes the same entry number, a later cancel of the group keeps that entry, and
|
||||
/// the journal replays to the same documents.
|
||||
#[test]
|
||||
fn a_canceled_undo_scope_leaves_its_cut_entries_out_of_the_group() {
|
||||
let mut s = Session::new();
|
||||
let rect = json!({"x": 10, "y": 10, "width": 100, "height": 50});
|
||||
s.execute("file.new", &json!({"width": 400, "height": 300})).unwrap();
|
||||
s.execute("file.new", &json!({"width": 400, "height": 300})).unwrap();
|
||||
s.execute("document.activate", &json!({"index": 0})).unwrap();
|
||||
s.begin_undo_group();
|
||||
s.execute("shape.rectangle", &rect).unwrap();
|
||||
let scope = s.begin_undo_scope().unwrap();
|
||||
s.execute("shape.rectangle", &rect).unwrap();
|
||||
s.end_undo_scope(scope, true);
|
||||
let journal = s.journal.len();
|
||||
// The switch takes the entry number the scope's edit had, and the rectangle in the second document follows it.
|
||||
s.execute("document.activate", &json!({"index": 1})).unwrap();
|
||||
s.execute("shape.rectangle", &rect).unwrap();
|
||||
s.end_undo_group(true);
|
||||
let objects = s.documents().iter().map(|d| d.doc.layers[0].children().map_or(0, |c| c.len())).collect::<Vec<_>>();
|
||||
assert_eq!(objects, [0, 1]);
|
||||
assert_eq!(s.journal.len(), journal + 1, "only the group's own edit leaves the journal");
|
||||
let r = replayed(&s);
|
||||
assert_eq!(documents(&r), documents(&s));
|
||||
assert_eq!(r.active_index(), s.active_index());
|
||||
}
|
||||
|
||||
/// A move drag is named for what its last preview did: Alt pressed or released during the drag
|
||||
/// turns it into a copy or back (the Selection and Direct Selection tools).
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user