3434import sys
3535import tempfile
3636import textwrap
37+ import time
3738import traceback
3839import unicodedata
3940from itertools import takewhile
5354import bpython .autocomplete as autocomplete
5455
5556
57+ class RuntimeTimer (object ):
58+ def __init__ (self ):
59+ self .reset_timer ()
60+ self .time = time .monotonic if hasattr (time , 'monotonic' ) else time .time
61+
62+ def __enter__ (self ):
63+ self .start = self .time ()
64+
65+ def __exit__ (self , ty , val , tb ):
66+ self .last_command = self .time () - self .start
67+ self .running_time += self .last_command
68+ return False
69+
70+ def reset_timer (self ):
71+ self .running_time = 0.0
72+ self .last_command = 0.0
73+
74+ def estimate (self ):
75+ return self .running_time - self .last_command
76+
5677class Interpreter (code .InteractiveInterpreter ):
5778
5879 def __init__ (self , locals = None , encoding = None ):
@@ -68,16 +89,28 @@ def __init__(self, locals=None, encoding=None):
6889 self .syntaxerror_callback = None
6990 # Unfortunately code.InteractiveInterpreter is a classic class, so no super()
7091 code .InteractiveInterpreter .__init__ (self , locals )
92+ self .timer = RuntimeTimer ()
93+
94+ def reset_running_time (self ):
95+ self .running_time = 0
96+
97+ if py3 :
7198
72- if not py3 :
99+ def runsource (self , source , filename = "<input>" , symbol = "single" ):
100+ with self .timer :
101+ return code .InteractiveInterpreter .runsource (self , source ,
102+ filename , symbol )
103+
104+ else :
73105
74106 def runsource (self , source , filename = '<input>' , symbol = 'single' ,
75107 encode = True ):
76- if encode :
77- source = '# coding: %s\n %s' % (self .encoding ,
78- source .encode (self .encoding ))
79- return code .InteractiveInterpreter .runsource (self , source ,
80- filename , symbol )
108+ with self .timer :
109+ if encode :
110+ source = '# coding: %s\n %s' % (self .encoding ,
111+ source .encode (self .encoding ))
112+ return code .InteractiveInterpreter .runsource (self , source ,
113+ filename , symbol )
81114
82115 def showsyntaxerror (self , filename = None ):
83116 """Override the regular handler, the code's copied and pasted from
@@ -792,25 +825,51 @@ def insert_into_history(self, s):
792825 except RuntimeError as e :
793826 self .interact .notify (str (e ))
794827
828+ def prompt_undo (self ):
829+ """Returns how many lines to undo, 0 means don't undo"""
830+ if (self .config .single_undo_time < 0 or
831+ self .interp .timer .estimate () < self .config .single_undo_time ):
832+ return 1
833+ est = self .interp .timer .estimate ()
834+ n = self .interact .file_prompt (
835+ _ ("Undo how many lines? (Undo will take up to ~%.1f seconds) [1]" )
836+ % (est ,))
837+ try :
838+ if n == '' :
839+ n = '1'
840+ n = int (n )
841+ except ValueError :
842+ self .interact .notify (_ ('Undo canceled' ), .1 )
843+ return 0
844+ else :
845+ if n == 0 :
846+ self .interact .notify (_ ('Undo canceled' ), .1 )
847+ return 0
848+ if n == 1 :
849+ self .interact .notify (_ ('Undoing 1 line... (est. %.1f seconds)' )
850+ % (est ,), .1 )
851+ else :
852+ self .interact .notify (_ ('Undoing %d lines... (est. %.1f seconds)' )
853+ % (n , est ), .1 )
854+ return n
855+
795856 def undo (self , n = 1 ):
796- """Go back in the undo history n steps and call reeavluate ()
857+ """Go back in the undo history n steps and call reevaluate ()
797858 Note that in the program this is called "Rewind" because I
798859 want it to be clear that this is by no means a true undo
799860 implementation, it is merely a convenience bonus."""
800861 if not self .history :
801862 return None
802863
864+ self .interp .timer .reset_timer ()
865+
803866 if len (self .history ) < n :
804867 n = len (self .history )
805868
806869 entries = list (self .rl_history .entries )
807870
808871 self .history = self .history [:- n ]
809- if (n == 1 and self .buffer and
810- hasattr (self , 'take_back_buffer_line' )):
811- self .take_back_buffer_line ()
812- else :
813- self .reevaluate ()
872+ self .reevaluate ()
814873
815874 self .rl_history .entries = entries
816875
0 commit comments