From a3f321a531554b51160f3fe7e6da1c269030f3b6 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 23 Nov 2022 13:02:00 -0600 Subject: [PATCH] Follow parent links when calculating changes since a revision The 'revisions' field on History can't be treated as linear: each Revision in the revisions Vec has a parent link and an optional child link. We can follow those to unroll the recent history. --- helix-core/src/history.rs | 31 +++++++++++++++++++++---------- helix-term/tests/test/commands.rs | 3 +++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs index 5f9fa71e4..825092423 100644 --- a/helix-core/src/history.rs +++ b/helix-core/src/history.rs @@ -126,16 +126,27 @@ impl History { match revision.cmp(&self.current) { Equal => None, - Greater => self.revisions[self.current + 1..=revision] - .iter() - .map(|revision| &revision.inversion) - .cloned() - .reduce(|acc, inversion| acc.compose(inversion)), - Less => self.revisions[revision + 1..=self.current] - .iter() - .map(|revision| &revision.transaction) - .cloned() - .reduce(|acc, transaction| acc.compose(transaction)), + Less => { + let mut child = self.revisions[revision].last_child?.get(); + let mut transaction = self.revisions[child].transaction.clone(); + while child != self.current { + child = self.revisions[child].last_child?.get(); + transaction = transaction.compose(self.revisions[child].transaction.clone()); + } + Some(transaction) + } + Greater => { + let mut inversion = self.revisions[revision].inversion.clone(); + let mut parent = self.revisions[revision].parent; + while parent != self.current { + parent = self.revisions[parent].parent; + if parent == 0 { + return None; + } + inversion = inversion.compose(self.revisions[parent].inversion.clone()); + } + Some(inversion) + } } } diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index 012957045..95bd95b73 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -306,5 +306,8 @@ async fn test_undo_redo() -> anyhow::Result<()> { // * Jump forward to line 1. test(("#[|]#", "[kduU", "#[|]#")).await?; + // In this case we 'redo' manually to ensure that the transactions are composing correctly. + test(("#[|]#", "[u[u", "#[|]#")).await?; + Ok(()) }