From 8e49f7a2d7e698d00bc7dcf41adf2e7772b13a5f Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 23 Nov 2022 09:35:07 -0600 Subject: [PATCH] Apply inversions to Views on undo/redo When using undo/redo, the history revision can be decremented. In that case we should apply the inversions since the given revision in History::changes_since. This prevents panics with jumplist operations when a session uses undo/redo to move the jumplist selection outside of the document. --- helix-core/src/history.rs | 24 ++++++++++++++---------- helix-term/src/ui/editor.rs | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs index 697f29b4ec982..f02e648b403eb 100644 --- a/helix-core/src/history.rs +++ b/helix-core/src/history.rs @@ -122,17 +122,21 @@ impl History { /// Returns the changes since the given revision composed into a transaction. /// Returns None if there are no changes between the current and given revisions. pub fn changes_since(&self, revision: usize) -> Option { - if self.at_root() || self.current >= revision { - return None; + if revision == self.current { + None + } else if revision > self.current { + self.revisions[self.current..revision] + .iter() + .map(|revision| &revision.inversion) + .cloned() + .reduce(|acc, inversion| acc.compose(inversion)) + } else { + self.revisions[revision + 1..=self.current] + .iter() + .map(|revision| &revision.transaction) + .cloned() + .reduce(|acc, transaction| acc.compose(transaction)) } - - // The bounds are checked in the if condition above: - // `revision` is known to be `< self.current`. - self.revisions[revision..self.current] - .iter() - .map(|revision| &revision.transaction) - .cloned() - .reduce(|acc, transaction| acc.compose(transaction)) } /// Undo the last edit. diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 44f89b77ed154..737125031e993 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1424,7 +1424,7 @@ impl Component for EditorView { // If the current document has been changed, apply the changes to all views. // This ensures that selections in jumplists follow changes. if doc.id() == original_doc_id - && doc.get_current_revision() > original_doc_revision + && doc.get_current_revision() != original_doc_revision { if let Some(transaction) = doc.history.get_mut().changes_since(original_doc_revision)