##// END OF EJS Templates
Avoid unnecessary calculation of indent on every line
Thomas Kluyver -
Show More
@@ -290,10 +290,11 b' class InputSplitter(object):'
290 isp.push(line)
290 isp.push(line)
291 print 'Input source was:\n', isp.source_reset(),
291 print 'Input source was:\n', isp.source_reset(),
292 """
292 """
293 # Number of spaces of indentation computed from input that has been pushed
293 # A cache for calculating the current indentation.
294 # so far. This is the attributes callers should query to get the current
294 # If the first value matches self.source, the second value is an integer
295 # indentation level, in order to provide auto-indent facilities.
295 # number of spaces for the current indentation. If the first value does not
296 indent_spaces = 0
296 # match, self.source has changed, and the indentation must be recalculated.
297 _indent_spaces_cache = None, None
297 # String, indicating the default input encoding. It is computed by default
298 # String, indicating the default input encoding. It is computed by default
298 # at initialization time via get_input_encoding(), but it can be reset by a
299 # at initialization time via get_input_encoding(), but it can be reset by a
299 # client with specific knowledge of the encoding.
300 # client with specific knowledge of the encoding.
@@ -327,7 +328,6 b' class InputSplitter(object):'
327
328
328 def reset(self):
329 def reset(self):
329 """Reset the input buffer and associated state."""
330 """Reset the input buffer and associated state."""
330 self.indent_spaces = 0
331 self._buffer[:] = []
331 self._buffer[:] = []
332 self.source = ''
332 self.source = ''
333 self.code = None
333 self.code = None
@@ -371,7 +371,7 b' class InputSplitter(object):'
371 if self._is_invalid:
371 if self._is_invalid:
372 return 'invalid', None
372 return 'invalid', None
373 elif self.push_accepts_more():
373 elif self.push_accepts_more():
374 return 'incomplete', self.indent_spaces
374 return 'incomplete', self.get_indent_spaces()
375 else:
375 else:
376 return 'complete', None
376 return 'complete', None
377 finally:
377 finally:
@@ -412,7 +412,6 b' class InputSplitter(object):'
412 if source.endswith('\\\n'):
412 if source.endswith('\\\n'):
413 return False
413 return False
414
414
415 self._update_indent()
416 try:
415 try:
417 with warnings.catch_warnings():
416 with warnings.catch_warnings():
418 warnings.simplefilter('error', SyntaxWarning)
417 warnings.simplefilter('error', SyntaxWarning)
@@ -470,7 +469,7 b' class InputSplitter(object):'
470 # If there's just a single line or AST node, and we're flush left, as is
469 # If there's just a single line or AST node, and we're flush left, as is
471 # the case after a simple statement such as 'a=1', we want to execute it
470 # the case after a simple statement such as 'a=1', we want to execute it
472 # straight away.
471 # straight away.
473 if self.indent_spaces==0:
472 if self.get_indent_spaces() == 0:
474 if len(self.source.splitlines()) <= 1:
473 if len(self.source.splitlines()) <= 1:
475 return False
474 return False
476
475
@@ -488,9 +487,15 b' class InputSplitter(object):'
488 # General fallback - accept more code
487 # General fallback - accept more code
489 return True
488 return True
490
489
491 def _update_indent(self):
490 def get_indent_spaces(self):
491 sourcefor, n = self._indent_spaces_cache
492 if sourcefor == self.source:
493 return n
494
492 # self.source always has a trailing newline
495 # self.source always has a trailing newline
493 self.indent_spaces = find_next_indent(self.source[:-1])
496 n = find_next_indent(self.source[:-1])
497 self._indent_spaces_cache = (self.source, n)
498 return n
494
499
495 def _store(self, lines, buffer=None, store='source'):
500 def _store(self, lines, buffer=None, store='source'):
496 """Store one or more lines of input.
501 """Store one or more lines of input.
@@ -1940,7 +1940,7 b' class InteractiveShell(SingletonConfigurable):'
1940
1940
1941 def _indent_current_str(self):
1941 def _indent_current_str(self):
1942 """return the current level of indentation as a string"""
1942 """return the current level of indentation as a string"""
1943 return self.input_splitter.indent_spaces * ' '
1943 return self.input_splitter.get_indent_spaces() * ' '
1944
1944
1945 #-------------------------------------------------------------------------
1945 #-------------------------------------------------------------------------
1946 # Things related to text completion
1946 # Things related to text completion
@@ -37,7 +37,7 b' def mini_interactive_loop(input_func):'
37 # input indefinitely, until some exit/quit command was issued. Here we
37 # input indefinitely, until some exit/quit command was issued. Here we
38 # only illustrate the basic inner loop.
38 # only illustrate the basic inner loop.
39 while isp.push_accepts_more():
39 while isp.push_accepts_more():
40 indent = ' '*isp.indent_spaces
40 indent = ' '*isp.get_indent_spaces()
41 prompt = '>>> ' + indent
41 prompt = '>>> ' + indent
42 line = indent + input_func(prompt)
42 line = indent + input_func(prompt)
43 isp.push(line)
43 isp.push(line)
@@ -132,7 +132,7 b' class InputSplitterTestCase(unittest.TestCase):'
132 isp.push('x=1')
132 isp.push('x=1')
133 isp.reset()
133 isp.reset()
134 self.assertEqual(isp._buffer, [])
134 self.assertEqual(isp._buffer, [])
135 self.assertEqual(isp.indent_spaces, 0)
135 self.assertEqual(isp.get_indent_spaces(), 0)
136 self.assertEqual(isp.source, '')
136 self.assertEqual(isp.source, '')
137 self.assertEqual(isp.code, None)
137 self.assertEqual(isp.code, None)
138 self.assertEqual(isp._is_complete, False)
138 self.assertEqual(isp._is_complete, False)
@@ -149,21 +149,21 b' class InputSplitterTestCase(unittest.TestCase):'
149 def test_indent(self):
149 def test_indent(self):
150 isp = self.isp # shorthand
150 isp = self.isp # shorthand
151 isp.push('x=1')
151 isp.push('x=1')
152 self.assertEqual(isp.indent_spaces, 0)
152 self.assertEqual(isp.get_indent_spaces(), 0)
153 isp.push('if 1:\n x=1')
153 isp.push('if 1:\n x=1')
154 self.assertEqual(isp.indent_spaces, 4)
154 self.assertEqual(isp.get_indent_spaces(), 4)
155 isp.push('y=2\n')
155 isp.push('y=2\n')
156 self.assertEqual(isp.indent_spaces, 0)
156 self.assertEqual(isp.get_indent_spaces(), 0)
157
157
158 def test_indent2(self):
158 def test_indent2(self):
159 isp = self.isp
159 isp = self.isp
160 isp.push('if 1:')
160 isp.push('if 1:')
161 self.assertEqual(isp.indent_spaces, 4)
161 self.assertEqual(isp.get_indent_spaces(), 4)
162 isp.push(' x=1')
162 isp.push(' x=1')
163 self.assertEqual(isp.indent_spaces, 4)
163 self.assertEqual(isp.get_indent_spaces(), 4)
164 # Blank lines shouldn't change the indent level
164 # Blank lines shouldn't change the indent level
165 isp.push(' '*2)
165 isp.push(' '*2)
166 self.assertEqual(isp.indent_spaces, 4)
166 self.assertEqual(isp.get_indent_spaces(), 4)
167
167
168 def test_indent3(self):
168 def test_indent3(self):
169 isp = self.isp
169 isp = self.isp
@@ -171,75 +171,75 b' class InputSplitterTestCase(unittest.TestCase):'
171 # shouldn't get confused.
171 # shouldn't get confused.
172 isp.push("if 1:")
172 isp.push("if 1:")
173 isp.push(" x = (1+\n 2)")
173 isp.push(" x = (1+\n 2)")
174 self.assertEqual(isp.indent_spaces, 4)
174 self.assertEqual(isp.get_indent_spaces(), 4)
175
175
176 def test_indent4(self):
176 def test_indent4(self):
177 isp = self.isp
177 isp = self.isp
178 # whitespace after ':' should not screw up indent level
178 # whitespace after ':' should not screw up indent level
179 isp.push('if 1: \n x=1')
179 isp.push('if 1: \n x=1')
180 self.assertEqual(isp.indent_spaces, 4)
180 self.assertEqual(isp.get_indent_spaces(), 4)
181 isp.push('y=2\n')
181 isp.push('y=2\n')
182 self.assertEqual(isp.indent_spaces, 0)
182 self.assertEqual(isp.get_indent_spaces(), 0)
183 isp.push('if 1:\t\n x=1')
183 isp.push('if 1:\t\n x=1')
184 self.assertEqual(isp.indent_spaces, 4)
184 self.assertEqual(isp.get_indent_spaces(), 4)
185 isp.push('y=2\n')
185 isp.push('y=2\n')
186 self.assertEqual(isp.indent_spaces, 0)
186 self.assertEqual(isp.get_indent_spaces(), 0)
187
187
188 def test_dedent_pass(self):
188 def test_dedent_pass(self):
189 isp = self.isp # shorthand
189 isp = self.isp # shorthand
190 # should NOT cause dedent
190 # should NOT cause dedent
191 isp.push('if 1:\n passes = 5')
191 isp.push('if 1:\n passes = 5')
192 self.assertEqual(isp.indent_spaces, 4)
192 self.assertEqual(isp.get_indent_spaces(), 4)
193 isp.push('if 1:\n pass')
193 isp.push('if 1:\n pass')
194 self.assertEqual(isp.indent_spaces, 0)
194 self.assertEqual(isp.get_indent_spaces(), 0)
195 isp.push('if 1:\n pass ')
195 isp.push('if 1:\n pass ')
196 self.assertEqual(isp.indent_spaces, 0)
196 self.assertEqual(isp.get_indent_spaces(), 0)
197
197
198 def test_dedent_break(self):
198 def test_dedent_break(self):
199 isp = self.isp # shorthand
199 isp = self.isp # shorthand
200 # should NOT cause dedent
200 # should NOT cause dedent
201 isp.push('while 1:\n breaks = 5')
201 isp.push('while 1:\n breaks = 5')
202 self.assertEqual(isp.indent_spaces, 4)
202 self.assertEqual(isp.get_indent_spaces(), 4)
203 isp.push('while 1:\n break')
203 isp.push('while 1:\n break')
204 self.assertEqual(isp.indent_spaces, 0)
204 self.assertEqual(isp.get_indent_spaces(), 0)
205 isp.push('while 1:\n break ')
205 isp.push('while 1:\n break ')
206 self.assertEqual(isp.indent_spaces, 0)
206 self.assertEqual(isp.get_indent_spaces(), 0)
207
207
208 def test_dedent_continue(self):
208 def test_dedent_continue(self):
209 isp = self.isp # shorthand
209 isp = self.isp # shorthand
210 # should NOT cause dedent
210 # should NOT cause dedent
211 isp.push('while 1:\n continues = 5')
211 isp.push('while 1:\n continues = 5')
212 self.assertEqual(isp.indent_spaces, 4)
212 self.assertEqual(isp.get_indent_spaces(), 4)
213 isp.push('while 1:\n continue')
213 isp.push('while 1:\n continue')
214 self.assertEqual(isp.indent_spaces, 0)
214 self.assertEqual(isp.get_indent_spaces(), 0)
215 isp.push('while 1:\n continue ')
215 isp.push('while 1:\n continue ')
216 self.assertEqual(isp.indent_spaces, 0)
216 self.assertEqual(isp.get_indent_spaces(), 0)
217
217
218 def test_dedent_raise(self):
218 def test_dedent_raise(self):
219 isp = self.isp # shorthand
219 isp = self.isp # shorthand
220 # should NOT cause dedent
220 # should NOT cause dedent
221 isp.push('if 1:\n raised = 4')
221 isp.push('if 1:\n raised = 4')
222 self.assertEqual(isp.indent_spaces, 4)
222 self.assertEqual(isp.get_indent_spaces(), 4)
223 isp.push('if 1:\n raise TypeError()')
223 isp.push('if 1:\n raise TypeError()')
224 self.assertEqual(isp.indent_spaces, 0)
224 self.assertEqual(isp.get_indent_spaces(), 0)
225 isp.push('if 1:\n raise')
225 isp.push('if 1:\n raise')
226 self.assertEqual(isp.indent_spaces, 0)
226 self.assertEqual(isp.get_indent_spaces(), 0)
227 isp.push('if 1:\n raise ')
227 isp.push('if 1:\n raise ')
228 self.assertEqual(isp.indent_spaces, 0)
228 self.assertEqual(isp.get_indent_spaces(), 0)
229
229
230 def test_dedent_return(self):
230 def test_dedent_return(self):
231 isp = self.isp # shorthand
231 isp = self.isp # shorthand
232 # should NOT cause dedent
232 # should NOT cause dedent
233 isp.push('if 1:\n returning = 4')
233 isp.push('if 1:\n returning = 4')
234 self.assertEqual(isp.indent_spaces, 4)
234 self.assertEqual(isp.get_indent_spaces(), 4)
235 isp.push('if 1:\n return 5 + 493')
235 isp.push('if 1:\n return 5 + 493')
236 self.assertEqual(isp.indent_spaces, 0)
236 self.assertEqual(isp.get_indent_spaces(), 0)
237 isp.push('if 1:\n return')
237 isp.push('if 1:\n return')
238 self.assertEqual(isp.indent_spaces, 0)
238 self.assertEqual(isp.get_indent_spaces(), 0)
239 isp.push('if 1:\n return ')
239 isp.push('if 1:\n return ')
240 self.assertEqual(isp.indent_spaces, 0)
240 self.assertEqual(isp.get_indent_spaces(), 0)
241 isp.push('if 1:\n return(0)')
241 isp.push('if 1:\n return(0)')
242 self.assertEqual(isp.indent_spaces, 0)
242 self.assertEqual(isp.get_indent_spaces(), 0)
243
243
244 def test_push(self):
244 def test_push(self):
245 isp = self.isp
245 isp = self.isp
@@ -508,7 +508,7 b" if __name__ == '__main__':"
508 while True:
508 while True:
509 prompt = start_prompt
509 prompt = start_prompt
510 while isp.push_accepts_more():
510 while isp.push_accepts_more():
511 indent = ' '*isp.indent_spaces
511 indent = ' '*isp.get_indent_spaces()
512 if autoindent:
512 if autoindent:
513 line = indent + input(prompt+indent)
513 line = indent + input(prompt+indent)
514 else:
514 else:
General Comments 0
You need to be logged in to leave comments. Login now