##// END OF EJS Templates
Refactor multiline input and prompt management.
Fernando Perez -
Show More
1 NO CONTENT: modified file chmod 100644 => 100755
NO CONTENT: modified file chmod 100644 => 100755
@@ -54,8 +54,9 b' class DisplayHook(Configurable):'
54 """
54 """
55
55
56 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
56 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
57
57 # Each call to the In[] prompt raises it by 1, even the first.
58 # Each call to the In[] prompt raises it by 1, even the first.
58 prompt_count = Int(0)
59 #prompt_count = Int(0)
59
60
60 def __init__(self, shell=None, cache_size=1000,
61 def __init__(self, shell=None, cache_size=1000,
61 colors='NoColor', input_sep='\n',
62 colors='NoColor', input_sep='\n',
@@ -114,6 +115,14 b' class DisplayHook(Configurable):'
114 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
115 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
115 self.shell.user_ns.update(to_user_ns)
116 self.shell.user_ns.update(to_user_ns)
116
117
118 @property
119 def prompt_count(self):
120 return self.shell.execution_count
121
122 @prompt_count.setter
123 def _set_prompt_count(self, val):
124 raise ValueError('prompt count is read only')
125
117 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
126 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
118 if p_str is None:
127 if p_str is None:
119 if self.do_full_cache:
128 if self.do_full_cache:
@@ -397,6 +397,9 b' class InteractiveShell(Configurable, Magic):'
397 # Indentation management
397 # Indentation management
398 self.indent_current_nsp = 0
398 self.indent_current_nsp = 0
399
399
400 # Increasing execution counter
401 self.execution_count = 0
402
400 def init_environment(self):
403 def init_environment(self):
401 """Any changes we need to make to the user's environment."""
404 """Any changes we need to make to the user's environment."""
402 pass
405 pass
@@ -978,6 +981,9 b' class InteractiveShell(Configurable, Magic):'
978 self.input_hist_raw[:] = []
981 self.input_hist_raw[:] = []
979 self.output_hist.clear()
982 self.output_hist.clear()
980
983
984 # Reset counter used to index all histories
985 self.execution_count = 0
986
981 # Restore the user namespaces to minimal usability
987 # Restore the user namespaces to minimal usability
982 self.init_user_ns()
988 self.init_user_ns()
983
989
@@ -2186,42 +2192,68 b' class InteractiveShell(Configurable, Magic):'
2186 # needs to go into the translated history and get executed (the
2192 # needs to go into the translated history and get executed (the
2187 # original cell may contain non-python syntax).
2193 # original cell may contain non-python syntax).
2188 ipy_cell = ''.join(blocks)
2194 ipy_cell = ''.join(blocks)
2189
2190 # Single-block input should behave like an interactive prompt
2191 if len(blocks) == 1:
2192 self.runlines(blocks[0])
2193 return
2194
2195
2195 # In multi-block input, if the last block is a simple (one-two lines)
2196 # Each cell is a *single* input, regardless of how many lines it has
2196 # expression, run it in single mode so it produces output. Otherwise
2197 self.execution_count += 1
2197 # just feed the whole thing to runcode.
2198
2198 # This seems like a reasonable usability design.
2199 # Store raw and processed history
2199 last = blocks[-1]
2200 self.input_hist_raw.append(cell)
2200 last_nlines = len(last.splitlines())
2201 self.input_hist.append(ipy_cell)
2201
2202
2202 # Note: below, whenever we call runcode, we must sync history
2203 # All user code execution must happen with our context managers active
2203 # ourselves, because runcode is NOT meant to manage history at all.
2204 with nested(self.builtin_trap, self.display_trap):
2204 if last_nlines < 2:
2205 # Single-block input should behave like an interactive prompt
2205 # Here we consider the cell split between 'body' and 'last', store
2206 if len(blocks) == 1:
2206 # all history and execute 'body', and if successful, then proceed
2207 return self.run_one_block(blocks[0])
2207 # to execute 'last'.
2208
2208
2209 # In multi-block input, if the last block is a simple (one-two
2209 # Raw history must contain the unmodified cell
2210 # lines) expression, run it in single mode so it produces output.
2210 raw_body = '\n'.join(cell.splitlines()[:-last_nlines])+'\n'
2211 # Otherwise just feed the whole thing to runcode. This seems like
2211 self.input_hist_raw.append(raw_body)
2212 # a reasonable usability design.
2212 # Get the main body to run as a cell
2213 last = blocks[-1]
2213 ipy_body = ''.join(blocks[:-1])
2214 last_nlines = len(last.splitlines())
2214 self.input_hist.append(ipy_body)
2215
2215 retcode = self.runcode(ipy_body, post_execute=False)
2216 # Note: below, whenever we call runcode, we must sync history
2216 if retcode==0:
2217 # ourselves, because runcode is NOT meant to manage history at all.
2217 # And the last expression via runlines so it produces output
2218 if last_nlines < 2:
2218 self.runlines(last)
2219 # Here we consider the cell split between 'body' and 'last',
2220 # store all history and execute 'body', and if successful, then
2221 # proceed to execute 'last'.
2222
2223 # Get the main body to run as a cell
2224 ipy_body = ''.join(blocks[:-1])
2225 retcode = self.runcode(ipy_body, post_execute=False)
2226 if retcode==0:
2227 # And the last expression via runlines so it produces output
2228 self.run_one_block(last)
2229 else:
2230 # Run the whole cell as one entity, storing both raw and
2231 # processed input in history
2232 self.runcode(ipy_cell)
2233
2234 def run_one_block(self, block):
2235 """Run a single interactive block.
2236
2237 If the block is single-line, dynamic transformations are applied to it
2238 (like automagics, autocall and alias recognition).
2239 """
2240 if len(block.splitlines()) <= 1:
2241 out = self.run_single_line(block)
2219 else:
2242 else:
2220 # Run the whole cell as one entity, storing both raw and processed
2243 out = self.runcode(block)
2221 # input in history
2244 return out
2222 self.input_hist_raw.append(cell)
2245
2223 self.input_hist.append(ipy_cell)
2246 def run_single_line(self, line):
2224 self.runcode(ipy_cell)
2247 """Run a single-line interactive statement.
2248
2249 This assumes the input has been transformed to IPython syntax by
2250 applying all static transformations (those with an explicit prefix like
2251 % or !), but it will further try to apply the dynamic ones.
2252
2253 It does not update history.
2254 """
2255 tline = self.prefilter_manager.prefilter_line(line)
2256 return self.runsource(tline)
2225
2257
2226 def runlines(self, lines, clean=False):
2258 def runlines(self, lines, clean=False):
2227 """Run a string of one or more lines of source.
2259 """Run a string of one or more lines of source.
@@ -2421,6 +2453,7 b' class InteractiveShell(Configurable, Magic):'
2421 more = self.runsource('\n'.join(self.buffer), self.filename)
2453 more = self.runsource('\n'.join(self.buffer), self.filename)
2422 if not more:
2454 if not more:
2423 self.resetbuffer()
2455 self.resetbuffer()
2456 self.execution_count += 1
2424 return more
2457 return more
2425
2458
2426 def resetbuffer(self):
2459 def resetbuffer(self):
@@ -214,9 +214,11 b' which already exists. But you must first start the logging process with'
214 # but if the opposite is true (a macro can produce multiple inputs
214 # but if the opposite is true (a macro can produce multiple inputs
215 # with no output display called), then bring the output counter in
215 # with no output display called), then bring the output counter in
216 # sync:
216 # sync:
217 last_num = len(input_hist)-1
217 ## last_num = len(input_hist)-1
218 if in_num != last_num:
218 ## if in_num != last_num:
219 in_num = self.shell.displayhook.prompt_count = last_num
219 ## pass # dbg
220 ## #in_num = self.shell.execution_count = last_num
221
220 new_i = '_i%s' % in_num
222 new_i = '_i%s' % in_num
221 if continuation:
223 if continuation:
222 self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line_mod)
224 self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line_mod)
@@ -372,15 +372,7 b' class Prompt1(BasePrompt):'
372 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
372 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
373 self.col_norm_ni = Colors.normal
373 self.col_norm_ni = Colors.normal
374
374
375 def peek_next_prompt(self):
376 """Get the next prompt, but don't increment the counter."""
377 self.cache.prompt_count += 1
378 next_prompt = str_safe(self.p_str)
379 self.cache.prompt_count -= 1
380 return next_prompt
381
382 def __str__(self):
375 def __str__(self):
383 self.cache.prompt_count += 1
384 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
376 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
385 return str_safe(self.p_str)
377 return str_safe(self.p_str)
386
378
@@ -227,6 +227,11 b' class TerminalInteractiveShell(InteractiveShell):'
227 self.readline_startup_hook(self.pre_readline)
227 self.readline_startup_hook(self.pre_readline)
228 # exit_now is set by a call to %Exit or %Quit, through the
228 # exit_now is set by a call to %Exit or %Quit, through the
229 # ask_exit callback.
229 # ask_exit callback.
230
231 # Before showing any prompts, if the counter is at zero, we execute an
232 # empty line to ensure the user only sees prompts starting at one.
233 if self.execution_count == 0:
234 self.push_line('\n')
230
235
231 while not self.exit_now:
236 while not self.exit_now:
232 self.hooks.pre_prompt_hook()
237 self.hooks.pre_prompt_hook()
@@ -238,8 +238,9 b' class Kernel(Configurable):'
238 status = u'ok'
238 status = u'ok'
239
239
240 reply_content[u'status'] = status
240 reply_content[u'status'] = status
241 # Compute the execution counter so clients can display prompts
241
242 reply_content['execution_count'] = shell.displayhook.prompt_count
242 # Return the execution counter so clients can display prompts
243 reply_content['execution_count'] = shell.execution_count
243
244
244 # FIXME - fish exception info out of shell, possibly left there by
245 # FIXME - fish exception info out of shell, possibly left there by
245 # runlines. We'll need to clean up this logic later.
246 # runlines. We'll need to clean up this logic later.
General Comments 0
You need to be logged in to leave comments. Login now