<s> import string <EOL> from Tkinter import * <EOL> from idlelib . Delegator import Delegator <EOL> class UndoDelegator ( Delegator ) : <EOL> max_undo = <NUM_LIT:1000> <EOL> def __init__ ( self ) : <EOL> Delegator . __init__ ( self ) <EOL> self . reset_undo ( ) <EOL> def setdelegate ( self , delegate ) : <EOL> if self . delegate is not None : <EOL> self . unbind ( "<STR_LIT>" ) <EOL> self . unbind ( "<STR_LIT>" ) <EOL> self . unbind ( "<STR_LIT>" ) <EOL> Delegator . setdelegate ( self , delegate ) <EOL> if delegate is not None : <EOL> self . bind ( "<STR_LIT>" , self . undo_event ) <EOL> self . bind ( "<STR_LIT>" , self . redo_event ) <EOL> self . bind ( "<STR_LIT>" , self . dump_event ) <EOL> def dump_event ( self , event ) : <EOL> from pprint import pprint <EOL> pprint ( self . undolist [ : self . pointer ] ) <EOL> print "<STR_LIT>" , self . pointer , <EOL> print "<STR_LIT>" , self . saved , <EOL> print "<STR_LIT>" , self . can_merge , <EOL> print "<STR_LIT>" , self . get_saved ( ) <EOL> pprint ( self . undolist [ self . pointer : ] ) <EOL> return "<STR_LIT>" <EOL> def reset_undo ( self ) : <EOL> self . was_saved = - <NUM_LIT:1> <EOL> self . pointer = <NUM_LIT:0> <EOL> self . undolist = [ ] <EOL> self . undoblock = <NUM_LIT:0> <EOL> self . set_saved ( <NUM_LIT:1> ) <EOL> def set_saved ( self , flag ) : <EOL> if flag : <EOL> self . saved = self . pointer <EOL> else : <EOL> self . saved = - <NUM_LIT:1> <EOL> self . can_merge = False <EOL> self . check_saved ( ) <EOL> def get_saved ( self ) : <EOL> return self . saved == self . pointer <EOL> saved_change_hook = None <EOL> def set_saved_change_hook ( self , hook ) : <EOL> self . saved_change_hook = hook <EOL> was_saved = - <NUM_LIT:1> <EOL> def check_saved ( self ) : <EOL> is_saved = self . get_saved ( ) <EOL> if is_saved != self . was_saved : <EOL> self . was_saved = is_saved <EOL> if self . saved_change_hook : <EOL> self . saved_change_hook ( ) <EOL> def insert ( self , index , chars , tags = None ) : <EOL> self . addcmd ( InsertCommand ( index , chars , tags ) ) <EOL> def delete ( self , index1 , index2 = None ) : <EOL> self . addcmd ( DeleteCommand ( index1 , index2 ) ) <EOL> def undo_block_start ( self ) : <EOL> if self . undoblock == <NUM_LIT:0> : <EOL> self . undoblock = CommandSequence ( ) <EOL> self . undoblock . bump_depth ( ) <EOL> def undo_block_stop ( self ) : <EOL> if self . undoblock . bump_depth ( - <NUM_LIT:1> ) == <NUM_LIT:0> : <EOL> cmd = self . undoblock <EOL> self . undoblock = <NUM_LIT:0> <EOL> if len ( cmd ) > <NUM_LIT:0> : <EOL> if len ( cmd ) == <NUM_LIT:1> : <EOL> cmd = cmd . getcmd ( <NUM_LIT:0> ) <EOL> self . addcmd ( cmd , <NUM_LIT:0> ) <EOL> def addcmd ( self , cmd , execute = True ) : <EOL> if execute : <EOL> cmd . do ( self . delegate ) <EOL> if self . undoblock != <NUM_LIT:0> : <EOL> self . undoblock . append ( cmd ) <EOL> return <EOL> if self . can_merge and self . pointer > <NUM_LIT:0> : <EOL> lastcmd = self . undolist [ self . pointer - <NUM_LIT:1> ] <EOL> if lastcmd . merge ( cmd ) : <EOL> return <EOL> self . undolist [ self . pointer : ] = [ cmd ] <EOL> if self . saved > self . pointer : <EOL> self . saved = - <NUM_LIT:1> <EOL> self . pointer = self . pointer + <NUM_LIT:1> <EOL> if len ( self . undolist ) > self . max_undo : <EOL> del self . undolist [ <NUM_LIT:0> ] <EOL> self . pointer = self . pointer - <NUM_LIT:1> <EOL> if self . saved >= <NUM_LIT:0> : <EOL> self . saved = self . saved - <NUM_LIT:1> <EOL> self . can_merge = True <EOL> self . check_saved ( ) <EOL> def undo_event ( self , event ) : <EOL> if self . pointer == <NUM_LIT:0> : <EOL> self . bell ( ) <EOL> return "<STR_LIT>" <EOL> cmd = self . undolist [ self . pointer - <NUM_LIT:1> ] <EOL> cmd . undo ( self . delegate ) <EOL> self . pointer = self . pointer - <NUM_LIT:1> <EOL> self . can_merge = False <EOL> self . check_saved ( ) <EOL> return "<STR_LIT>" <EOL> def redo_event ( self , event ) : <EOL> if self . pointer >= len ( self . undolist ) : <EOL> self . bell ( ) <EOL> return "<STR_LIT>" <EOL> cmd = self . undolist [ self . pointer ] <EOL> cmd . redo ( self . delegate ) <EOL> self . pointer = self . pointer + <NUM_LIT:1> <EOL> self . can_merge = False <EOL> self . check_saved ( ) <EOL> return "<STR_LIT>" <EOL> class Command : <EOL> tags = None <EOL> def __init__ ( self , index1 , index2 , chars , tags = None ) : <EOL> self . marks_before = { } <EOL> self . marks_after = { } <EOL> self . index1 = index1 <EOL> self . index2 = index2 <EOL> self . chars = chars <EOL> if tags : <EOL> self . tags = tags <EOL> def __repr__ ( self ) : <EOL> s = self . __class__ . __name__ <EOL> t = ( self . index1 , self . index2 , self . chars , self . tags ) <EOL> if self . tags is None : <EOL> t = t [ : - <NUM_LIT:1> ] <EOL> return s + repr ( t ) <EOL> def do ( self , text ) : <EOL> pass <EOL> def redo ( self , text ) : <EOL> pass <EOL> def undo ( self , text ) : <EOL> pass <EOL> def merge ( self , cmd ) : <EOL> return <NUM_LIT:0> <EOL> def save_marks ( self , text ) : <EOL> marks = { } <EOL> for name in text . mark_names ( ) : <EOL> if name != "<STR_LIT>" and name != "<STR_LIT>" : <EOL> marks [ name ] = text . index ( name ) <EOL> return marks <EOL> def set_marks ( self , text , marks ) : <EOL> for name , index in marks . items ( ) : <EOL> text . mark_set ( name , index ) <EOL> class InsertCommand ( Command ) : <EOL> def __init__ ( self , index1 , chars , tags = None ) : <EOL> Command . __init__ ( self , index1 , None , chars , tags ) <EOL> def do ( self , text ) : <EOL> self . marks_before = self . save_marks ( text ) <EOL> self . index1 = text . index ( self . index1 ) <EOL> if text . compare ( self . index1 , "<STR_LIT:>>" , "<STR_LIT>" ) : <EOL> self . index1 = text . index ( "<STR_LIT>" ) <EOL> text . insert ( self . index1 , self . chars , self . tags ) <EOL> self . index2 = text . index ( "<STR_LIT>" % ( self . index1 , len ( self . chars ) ) ) <EOL> self . marks_after = self . save_marks ( text ) <EOL> def redo ( self , text ) : <EOL> text . mark_set ( '<STR_LIT>' , self . index1 ) <EOL> text . insert ( self . index1 , self . chars , self . tags ) <EOL> self . set_marks ( text , self . marks_after ) <EOL> text . see ( '<STR_LIT>' ) <EOL> def undo ( self , text ) : <EOL> text . mark_set ( '<STR_LIT>' , self . index1 ) <EOL> text . delete ( self . index1 , self . index2 ) <EOL> self . set_marks ( text , self . marks_before ) <EOL> text . see ( '<STR_LIT>' ) <EOL> def merge ( self , cmd ) : <EOL> if self . __class__ is not cmd . __class__ : <EOL> return False <EOL> if self . index2 != cmd . index1 : <EOL> return False <EOL> if self . tags != cmd . tags : <EOL> return False <EOL> if len ( cmd . chars ) != <NUM_LIT:1> : <EOL> return False <EOL> if self . chars and self . classify ( self . chars [ - <NUM_LIT:1> ] ) != self . classify ( cmd . chars ) : <EOL> return False <EOL> self . index2 = cmd . index2 <EOL> self . chars = self . chars + cmd . chars <EOL> return True <EOL> alphanumeric = string . ascii_letters + string . digits + "<STR_LIT:_>" <EOL> def classify ( self , c ) : <EOL> if c in self . alphanumeric : <EOL> return "<STR_LIT>" <EOL> if c == "<STR_LIT:\n>" : <EOL> return "<STR_LIT>" <EOL> return "<STR_LIT>" <EOL> class DeleteCommand ( Command ) : <EOL> def __init__ ( self , index1 , index2 = None ) : <EOL> Command . __init__ ( self , index1 , index2 , None , None ) <EOL> def do ( self , text ) : <EOL> self . marks_before = self . save_marks ( text ) <EOL> self . index1 = text . index ( self . index1 ) <EOL> if self . index2 : <EOL> self . index2 = text . index ( self . index2 ) <EOL> else : <EOL> self . index2 = text . index ( self . index1 + "<STR_LIT>" ) <EOL> if text . compare ( self . index2 , "<STR_LIT:>>" , "<STR_LIT>" ) : <EOL> self . index2 = text . index ( "<STR_LIT>" ) <EOL> self . chars = text . get ( self . index1 , self . index2 ) <EOL> text . delete ( self . index1 , self . index2 ) <EOL> self . marks_after = self . save_marks ( text ) <EOL> def redo ( self , text ) : <EOL> text . mark_set ( '<STR_LIT>' , self . index1 ) <EOL> text . delete ( self . index1 , self . index2 ) <EOL> self . set_marks ( text , self . marks_after ) <EOL> text . see ( '<STR_LIT>' ) <EOL> def undo ( self , text ) : <EOL> text . mark_set ( '<STR_LIT>' , self . index1 ) <EOL> text . insert ( self . index1 , self . chars ) <EOL> self . set_marks ( text , self . marks_before ) <EOL> text . see ( '<STR_LIT>' ) <EOL> class CommandSequence ( Command ) : <EOL> def __init__ ( self ) : <EOL> self . cmds = [ ] <EOL> self . depth = <NUM_LIT:0> <EOL> def __repr__ ( self ) : <EOL> s = self . __class__ . __name__ <EOL> strs = [ ] <EOL> for cmd in self . cmds : <EOL> strs . append ( "<STR_LIT>" % ( cmd , ) ) <EOL> return s + "<STR_LIT>" + "<STR_LIT>" . join ( strs ) + "<STR_LIT>" <EOL> def __len__ ( self ) : <EOL> return len ( self . cmds ) <EOL> def append ( self , cmd ) : <EOL> self . cmds . append ( cmd ) <EOL> def getcmd ( self , i ) : <EOL> return self . cmds [ i ] <EOL> def redo ( self , text ) : <EOL> for cmd in self . cmds : <EOL> cmd . redo ( text ) <EOL> def undo ( self , text ) : <EOL> cmds = self . cmds [ : ] <EOL> cmds . reverse ( ) <EOL> for cmd in cmds : <EOL> cmd . undo ( text ) <EOL> def bump_depth ( self , incr = <NUM_LIT:1> ) : <EOL> self . depth = self . depth + incr <EOL> return self . depth <EOL> def main ( ) : <EOL> from idlelib . Percolator import Percolator <EOL> root = Tk ( ) <EOL> root . wm_protocol ( "<STR_LIT>" , root . quit ) <EOL> text = Text ( ) <EOL> text . pack ( ) <EOL> text . focus_set ( ) <EOL> p = Percolator ( text ) <EOL> d = UndoDelegator ( ) <EOL> p . insertfilter ( d ) <EOL> root . mainloop ( ) <EOL> if __name__ == "<STR_LIT:__main__>" : <EOL> main ( ) </s>
