Source code for stompy.undoer
"""
Generic support for recording operations, with the option
of undoing those operations.
TODO: Allow for commiting only part of the history. Currently
commit() discards the entire stack.
Could be better to maintain a linked list of checkpoints, each
checkpoint references one before it. Then commiting a checkpoint
means deleting its reference to commits before it.
"""
[docs]class OpHistory(object):
state='inactive' # 'recording','reverting'
[docs] class Checkpoint(object):
def __init__(self,serial,frame):
self.serial=serial
self.frame=frame
# Undo-history management - very generic.
op_stack_serial = 17
op_stack = None
abs_serial=0
[docs] def checkpoint(self):
assert self.state != 'reverting'
if self.op_stack is None:
self.op_stack_serial += 1
self.op_stack = []
self.state='recording'
return self.Checkpoint(self.op_stack_serial,len(self.op_stack))
[docs] def revert(self,cp):
if cp.serial != self.op_stack_serial:
raise ValueError( ("The current op stack has serial %d,"
"but your checkpoint is %s")%(self.op_stack_serial,
cp.serial) )
if self.state!='recording':
raise Exception("Tried to revert, but not recording")
try:
self.state='reverting'
while len(self.op_stack) > cp.frame:
self.pop_op()
finally:
self.state='recording'
[docs] def backstep(self):
if self.state!='recording':
raise Exception("backstep: state is not recording")
self.state='reverting'
try:
self.pop_op()
finally:
self.state='recording'
[docs] def commit(self):
assert self.state != 'reverting'
self.op_stack = None
self.op_stack_serial += 1
self.state='inactive'
[docs] def push_op(self,meth,*data,**kwdata):
self.abs_serial=self.abs_serial+1
if self.state!='recording':
return
if self.op_stack is not None:
self.op_stack.append( (meth,data,kwdata) )
[docs] def pop_op(self):
assert self.state=='reverting'
self.abs_serial=self.abs_serial+1
f = self.op_stack.pop()
self.log.debug("popping: %s"%( str(f) ) )
meth = f[0]
args = f[1]
kwargs = f[2]
meth(*args,**kwargs)
def __getstate__(self):
try:
d=super(OpHistory,self).__getstate__()
except AttributeError:
d = dict(self.__dict__)
d['op_stack']=None
d['state']='inactive'
return d