Handle exceptions thrown during do/undo/redo

This commit is contained in:
Corey Johnson
2012-11-12 15:59:44 -08:00
parent 448060a619
commit bb9c2e1bcb
2 changed files with 95 additions and 17 deletions

View File

@@ -98,3 +98,57 @@ describe "UndoManager", ->
undoManager.undo()
expect(buffer.lineForRow(0)).not.toContain("foo")
it "records transactions that occur prior to an exception", ->
spyOn(console, 'error')
buffer.setText("jumpstreet")
undoManager.transact ->
buffer.insert([0,0], "3")
buffer.insert([0,0], "2")
throw new Error("problem")
buffer.insert([0,0], "2")
expect(console.error).toHaveBeenCalled()
expect(buffer.lineForRow(0)).toBe "23jumpstreet"
undoManager.undo()
expect(buffer.lineForRow(0)).toBe "jumpstreet"
describe "when a `do` operation throws an exception", ->
it "clears the stack", ->
spyOn(console, 'error')
buffer.setText("word")
class FailingOperation
do: -> throw new Error("I'm a bad do operation")
buffer.insert([0,0], "1")
undoManager.pushOperation(new FailingOperation())
expect(console.error).toHaveBeenCalled()
undoManager.undo()
expect(buffer.lineForRow(0)).toBe "1word"
describe "when an `undo` operation throws an exception", ->
it "clears the stack", ->
spyOn(console, 'error')
buffer.setText("word")
class FailingOperation
undo: -> throw new Error("I'm a bad undo operation")
buffer.insert([0,0], "1")
undoManager.pushOperation(new FailingOperation())
undoManager.undo()
expect(console.error).toHaveBeenCalled()
expect(buffer.lineForRow(0)).toBe "1word"
describe "when an `redo` operation throws an exception", ->
it "clears the stack", ->
spyOn(console, 'error')
buffer.setText("word")
class FailingOperation
redo: -> throw new Error("I'm a bad undo operation")
buffer.insert([0,0], "1")
undoManager.pushOperation(new FailingOperation())
undoManager.undo()
undoManager.redo()
expect(console.error).toHaveBeenCalled()
expect(buffer.lineForRow(0)).toBe "1word"

View File

@@ -8,7 +8,10 @@ class UndoManager
currentTransaction: null
constructor: ->
@startBatchCallCount = 0
@clear()
clear: ->
@currentTransaction = null
@undoHistory = []
@redoHistory = []
@@ -18,29 +21,50 @@ class UndoManager
else
@undoHistory.push([operation])
@redoHistory = []
operation.do?(editSession)
try
operation.do?(editSession)
catch e
console.error e.stack
@clear()
transact: (fn) ->
safeFn = ->
try
fn()
catch e
console.error e.stack
if @currentTransaction
fn()
safeFn()
else
@currentTransaction = []
fn()
@undoHistory.push(@currentTransaction) if @currentTransaction.length
safeFn()
@undoHistory.push(@currentTransaction) if @currentTransaction?.length
@currentTransaction = null
undo: (editSession) ->
if batch = @undoHistory.pop()
opsInReverse = new Array(batch...)
opsInReverse.reverse()
op.undo?(editSession) for op in opsInReverse
@redoHistory.push batch
batch.oldSelectionRanges
try
if batch = @undoHistory.pop()
opsInReverse = new Array(batch...)
opsInReverse.reverse()
op.undo?(editSession) for op in opsInReverse
@redoHistory.push batch
batch.oldSelectionRanges
catch e
console.error e.stack
@clear()
redo: (editSession) ->
if batch = @redoHistory.pop()
for op in batch
op.do?(editSession)
op.redo?(editSession)
@undoHistory.push(batch)
batch.newSelectionRanges
try
if batch = @redoHistory.pop()
for op in batch
op.do?(editSession)
op.redo?(editSession)
@undoHistory.push(batch)
batch.newSelectionRanges
catch e
console.error e.stack
@clear()