on master help sign in
Apply inversions to Views on undo/redo
4a103dbMichael Davis
helix-core/src/history.rs+14−10
@@ -122,17 +122,21 @@ impl History {
122 /// Returns the changes since the given revision composed into a transaction.
122 /// Returns the changes since the given revision composed into a transaction.
123 /// Returns None if there are no changes between the current and given revisions.
123 /// Returns None if there are no changes between the current and given revisions.
124 pub fn changes_since(&self, revision: usize) -> Option<Transaction> {
124 pub fn changes_since(&self, revision: usize) -> Option<Transaction> {
125− if self.at_root() || self.current >= revision {
125+ use std::cmp::Ordering::*;
126− return None;
127− }
128
126
129− // The bounds are checked in the if condition above:
127+ match revision.cmp(&self.current) {
130− // `revision` is known to be `< self.current`.
128+ Equal => None,
129+ Greater => self.revisions[self.current + 1..=revision]
130+ .iter()
131+ .map(|revision| &revision.inversion)
132+ .cloned()
133+ .reduce(|acc, inversion| acc.compose(inversion)),
131− self.revisions[revision..self.current]
134+ Less => self.revisions[revision + 1..=self.current]
132− .iter()
135+ .iter()
133− .map(|revision| &revision.transaction)
136+ .map(|revision| &revision.transaction)
134− .cloned()
137+ .cloned()
135− .reduce(|acc, transaction| acc.compose(transaction))
138+ .reduce(|acc, transaction| acc.compose(transaction)),
139+ }
136 }
140 }
137
141
138 /// Undo the last edit.
142 /// Undo the last edit.
helix-term/src/ui/editor.rs+1−1
@@ -1424,7 +1424,7 @@ impl Component for EditorView {
1424 // If the current document has been changed, apply the changes to all views.
1424 // If the current document has been changed, apply the changes to all views.
1425 // This ensures that selections in jumplists follow changes.
1425 // This ensures that selections in jumplists follow changes.
1426 if doc.id() == original_doc_id
1426 if doc.id() == original_doc_id
1427− && doc.get_current_revision() > original_doc_revision
1427+ && doc.get_current_revision() != original_doc_revision
1428 {
1428 {
1429 if let Some(transaction) =
1429 if let Some(transaction) =
1430 doc.history.get_mut().changes_since(original_doc_revision)
1430 doc.history.get_mut().changes_since(original_doc_revision)
helix-term/tests/test/commands.rs+9
@@ -286,6 +286,15 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> {
286
286
287#[tokio::test(flavor = "multi_thread")]
287#[tokio::test(flavor = "multi_thread")]
288async fn test_undo_redo() -> anyhow::Result<()> {
288async fn test_undo_redo() -> anyhow::Result<()> {
289+ // A jumplist selection is created at a point which is undone.
290+ //
291+ // * 2[<space> Add two newlines at line start. We're now on line 3.
292+ // * <C-s> Save the selection on line 3 in the jumplist.
293+ // * u Undo the two newlines. We're now on line 1.
294+ // * <C-o><C-i> Jump forward an back again in the jumplist. This would panic
295+ // if the jumplist were not being updated correctly.
296+ test(("#[|]#", "2[<space><C-s>u<C-o><C-i>", "#[|]#")).await?;
297+
289 // A jumplist selection is passed through an edit and then an undo and then a redo.
298 // A jumplist selection is passed through an edit and then an undo and then a redo.
290 //
299 //
291 // * [<space> Add a newline at line start. We're now on line 2.
300 // * [<space> Add a newline at line start. We're now on line 2.