mirror of
https://github.com/atom/atom.git
synced 2026-02-19 02:44:29 -05:00
If an exception is thrown while running an operation, we clear the undo manager and re-throw it. But if we were in a transaction, we will commit it in a `finally` block. If the transaction is set to null, committing the transaction will then throw an exception which hides the original exception… we don't want that. Now clear just empties the current transaction out.
77 lines
1.7 KiB
CoffeeScript
77 lines
1.7 KiB
CoffeeScript
_ = require 'underscore'
|
|
|
|
# Internal: The object in charge of managing redo and undo operations.
|
|
module.exports =
|
|
class UndoManager
|
|
undoHistory: null
|
|
redoHistory: null
|
|
currentTransaction: null
|
|
|
|
constructor: ->
|
|
@clear()
|
|
|
|
clear: ->
|
|
@currentTransaction = [] if @currentTransaction?
|
|
@undoHistory = []
|
|
@redoHistory = []
|
|
|
|
pushOperation: (operation, editSession) ->
|
|
if @currentTransaction
|
|
@currentTransaction.push(operation)
|
|
else
|
|
@undoHistory.push([operation])
|
|
@redoHistory = []
|
|
|
|
try
|
|
operation.do?(editSession)
|
|
catch e
|
|
@clear()
|
|
throw e
|
|
|
|
transact: ->
|
|
isNewTransaction = not @currentTransaction?
|
|
@currentTransaction ?= []
|
|
isNewTransaction
|
|
|
|
commit: ->
|
|
unless @currentTransaction?
|
|
throw new Error("Trying to commit when there is no current transaction")
|
|
|
|
empty = @currentTransaction.length is 0
|
|
@undoHistory.push(@currentTransaction) unless empty
|
|
@currentTransaction = null
|
|
not empty
|
|
|
|
abort: ->
|
|
unless @currentTransaction?
|
|
throw new Error("Trying to abort when there is no current transaction")
|
|
|
|
if @commit()
|
|
@undo()
|
|
@redoHistory.pop()
|
|
|
|
undo: (editSession) ->
|
|
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
|
|
@clear()
|
|
throw e
|
|
|
|
redo: (editSession) ->
|
|
try
|
|
if batch = @redoHistory.pop()
|
|
for op in batch
|
|
op.do?(editSession)
|
|
op.redo?(editSession)
|
|
|
|
@undoHistory.push(batch)
|
|
batch.newSelectionRanges
|
|
catch e
|
|
@clear()
|
|
throw e
|