diff --git a/spec/atom/editor-spec.coffee b/spec/atom/editor-spec.coffee index e741fe8b3..fc3ce224d 100644 --- a/spec/atom/editor-spec.coffee +++ b/spec/atom/editor-spec.coffee @@ -596,12 +596,15 @@ describe "Editor", -> editor.trigger keydownEvent('delete') expect(buffer.getLine(12)).toBe '};' - describe "when undo events are triggered on the editor", -> - it "undoes the last change", -> + describe "when undo/redo events are triggered on the editor", -> + it "undoes/redoes the last change", -> buffer.insert [0, 0], "foo" editor.trigger 'undo' expect(buffer.getLine(0)).not.toContain "foo" + editor.trigger 'redo' + expect(buffer.getLine(0)).toContain "foo" + describe "when multiple lines are removed from the buffer (regression)", -> it "removes all of them from the dom", -> buffer.change(new Range([6, 24], [12, 0]), '') diff --git a/spec/atom/undo-manager-spec.coffee b/spec/atom/undo-manager-spec.coffee index 29a84810e..243ba0a1d 100644 --- a/spec/atom/undo-manager-spec.coffee +++ b/spec/atom/undo-manager-spec.coffee @@ -26,5 +26,36 @@ describe "UndoManager", -> undoManager.undo() expect(buffer.getLine(0)).toContain 'quicksort' - it "does not throw an exception when there is no last change", -> + it "does not throw an exception when there is nothing to undo", -> undoManager.undo() + + describe ".redo()", -> + beforeEach -> + buffer.change(new Range([0, 5], [0, 9]), '') + buffer.insert([0, 6], 'h') + buffer.insert([0, 10], 'y') + undoManager.undo() + undoManager.undo() + expect(buffer.getLine(0)).toContain 'qsort' + + it "redoes the last undone change", -> + undoManager.redo() + expect(buffer.getLine(0)).toContain 'qshort' + + undoManager.redo() + expect(buffer.getLine(0)).toContain 'qshorty' + + undoManager.undo() + expect(buffer.getLine(0)).toContain 'qshort' + + it "does not throw an exception when there is nothing to redo", -> + undoManager.redo() + undoManager.redo() + undoManager.redo() + + it "discards the redo history when there is a new change following an undo", -> + buffer.insert([0, 6], 'p') + expect(buffer.getText()).toContain 'qsport' + + undoManager.redo() + expect(buffer.getText()).toContain 'qsport' diff --git a/src/atom/editor.coffee b/src/atom/editor.coffee index fb9900989..81ef25b35 100644 --- a/src/atom/editor.coffee +++ b/src/atom/editor.coffee @@ -51,6 +51,7 @@ class Editor extends View 'meta-c': 'copy' 'meta-v': 'paste' 'meta-z': 'undo' + 'meta-Z': 'redo' @on 'move-right', => @moveCursorRight() @on 'move-left', => @moveCursorLeft() @@ -67,6 +68,7 @@ class Editor extends View @on 'copy', => @copySelection() @on 'paste', => @paste() @on 'undo', => @undo() + @on 'redo', => @redo() buildCursorAndSelection: -> @cursor = new Cursor(this) @@ -244,3 +246,6 @@ class Editor extends View undo: -> @undoManager.undo() + + redo: -> + @undoManager.redo() diff --git a/src/atom/undo-manager.coffee b/src/atom/undo-manager.coffee index e8a353fea..5222dfc00 100644 --- a/src/atom/undo-manager.coffee +++ b/src/atom/undo-manager.coffee @@ -1,17 +1,30 @@ module.exports = class UndoManager undoHistory: null - undoInProgress: null + redoHistory: null + preserveHistory: false constructor: (@buffer) -> @undoHistory = [] + @redoHistory = [] @buffer.on 'change', (op) => - @undoHistory.push(op) unless @undoInProgress + unless @preserveHistory + @undoHistory.push(op) + @redoHistory = [] undo: -> - return unless @undoHistory.length - op = @undoHistory.pop() - @undoInProgress = true - @buffer.change op.newRange, op.oldText - @undoInProgress = false + if op = @undoHistory.pop() + @preservingHistory => + @buffer.change op.newRange, op.oldText + @redoHistory.push op + redo: -> + if op = @redoHistory.pop() + @preservingHistory => + @buffer.change op.oldRange, op.newText + @undoHistory.push op + + preservingHistory: (fn) -> + @preserveHistory = true + fn() + @preserveHistory = false