##// END OF EJS Templates
Implement support for 'cell' mode with Ctrl-Enter....
Fernando Perez -
Show More
@@ -60,6 +60,7 b' Authors'
60 60 # Distributed under the terms of the BSD License. The full license is in
61 61 # the file COPYING, distributed as part of this software.
62 62 #-----------------------------------------------------------------------------
63 from __future__ import print_function
63 64
64 65 #-----------------------------------------------------------------------------
65 66 # Imports
@@ -71,6 +72,7 b' import sys'
71 72
72 73 # IPython modules
73 74 from IPython.utils.text import make_quoted_expr
75
74 76 #-----------------------------------------------------------------------------
75 77 # Globals
76 78 #-----------------------------------------------------------------------------
@@ -81,14 +83,14 b' from IPython.utils.text import make_quoted_expr'
81 83 # for all intents and purposes they constitute the 'IPython syntax', so they
82 84 # should be considered fixed.
83 85
84 ESC_SHELL = '!'
85 ESC_SH_CAP = '!!'
86 ESC_HELP = '?'
87 ESC_HELP2 = '??'
88 ESC_MAGIC = '%'
89 ESC_QUOTE = ','
90 ESC_QUOTE2 = ';'
91 ESC_PAREN = '/'
86 ESC_SHELL = '!' # Send line to underlying system shell
87 ESC_SH_CAP = '!!' # Send line to system shell and capture output
88 ESC_HELP = '?' # Find information about object
89 ESC_HELP2 = '??' # Find extra-detailed information about object
90 ESC_MAGIC = '%' # Call magic function
91 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
92 ESC_QUOTE2 = ';' # Quote all args as a single string, call
93 ESC_PAREN = '/' # Call first argument with rest of line as arguments
92 94
93 95 #-----------------------------------------------------------------------------
94 96 # Utilities
@@ -308,7 +310,7 b' class InputSplitter(object):'
308 310 ----------
309 311 input_mode : str
310 312
311 One of ['line', 'block']; default is 'line'.
313 One of ['line', 'cell']; default is 'line'.
312 314
313 315 The input_mode parameter controls how new inputs are used when fed via
314 316 the :meth:`push` method:
@@ -316,10 +318,11 b' class InputSplitter(object):'
316 318 - 'line': meant for line-oriented clients, inputs are appended one at a
317 319 time to the internal buffer and the whole buffer is compiled.
318 320
319 - 'block': meant for clients that can edit multi-line blocks of text at
320 a time. Each new input new input completely replaces all prior
321 inputs. Block mode is thus equivalent to prepending a full reset()
322 to every push() call.
321 - 'cell': meant for clients that can edit multi-line 'cells' of text at
322 a time. A cell can contain one or more blocks that can be compile in
323 'single' mode by Python. In this mode, each new input new input
324 completely replaces all prior inputs. Cell mode is thus equivalent
325 to prepending a full reset() to every push() call.
323 326 """
324 327 self._buffer = []
325 328 self._compile = codeop.CommandCompiler()
@@ -365,7 +368,7 b' class InputSplitter(object):'
365 368 this value is also stored as a private attribute (_is_complete), so it
366 369 can be queried at any time.
367 370 """
368 if self.input_mode == 'block':
371 if self.input_mode == 'cell':
369 372 self.reset()
370 373
371 374 # If the source code has leading blanks, add 'if 1:\n' to it
@@ -433,13 +436,31 b' class InputSplitter(object):'
433 436 backend which might convert the invalid syntax into valid Python via
434 437 one of the dynamic IPython mechanisms.
435 438 """
436
439
440 # With incomplete input, unconditionally accept more
437 441 if not self._is_complete:
438 442 return True
439 443
444 # If we already have complete input and we're flush left, the answer
445 # depends. In line mode, we're done. But in cell mode, we need to
446 # check how many blocks the input so far compiles into, because if
447 # there's already more than one full independent block of input, then
448 # the client has entered full 'cell' mode and is feeding lines that
449 # each is complete. In this case we should then keep accepting.
450 # The Qt terminal-like console does precisely this, to provide the
451 # convenience of terminal-like input of single expressions, but
452 # allowing the user (with a separate keystroke) to switch to 'cell'
453 # mode and type multiple expressions in one shot.
440 454 if self.indent_spaces==0:
441 return False
442
455 if self.input_mode=='line':
456 return False
457 else:
458 nblocks = len(split_blocks(''.join(self._buffer)))
459 if nblocks==1:
460 return False
461
462 # When input is complete, then termination is marked by an extra blank
463 # line at the end.
443 464 last_line = self.source.splitlines()[-1]
444 465 return bool(last_line and not last_line.isspace())
445 466
@@ -934,10 +955,10 b' class IPythonInputSplitter(InputSplitter):'
934 955 # line.
935 956 changed_input_mode = False
936 957
937 if len(lines_list)>1 and self.input_mode == 'block':
958 if len(lines_list)>1 and self.input_mode == 'cell':
938 959 self.reset()
939 960 changed_input_mode = True
940 saved_input_mode = 'block'
961 saved_input_mode = 'cell'
941 962 self.input_mode = 'line'
942 963
943 964 try:
@@ -204,7 +204,7 b' class InputSplitterTestCase(unittest.TestCase):'
204 204
205 205 def test_replace_mode(self):
206 206 isp = self.isp
207 isp.input_mode = 'block'
207 isp.input_mode = 'cell'
208 208 isp.push('x=1')
209 209 self.assertEqual(isp.source, 'x=1\n')
210 210 isp.push('x=2')
@@ -591,7 +591,7 b' class BlockIPythonInputTestCase(IPythonInputTestCase):'
591 591 test_push3 = test_split = lambda s: None
592 592
593 593 def setUp(self):
594 self.isp = isp.IPythonInputSplitter(input_mode='block')
594 self.isp = isp.IPythonInputSplitter(input_mode='cell')
595 595
596 596 def test_syntax_multiline(self):
597 597 isp = self.isp
@@ -363,6 +363,11 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
363 363 # disable the undo/redo history, but just to be safe:
364 364 self._control.setUndoRedoEnabled(False)
365 365
366 # Flush all state from the input splitter so the next round of
367 # reading input starts with a clean buffer.
368 self._input_splitter.reset()
369
370 # Call actual execution
366 371 self._execute(source, hidden)
367 372
368 373 else:
@@ -1,3 +1,5 b''
1 from __future__ import print_function
2
1 3 # Standard library imports
2 4 from collections import namedtuple
3 5 import signal
@@ -114,7 +116,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
114 116 self._copy_raw_action = QtGui.QAction('Copy (Raw Text)', None)
115 117 self._hidden = False
116 118 self._highlighter = FrontendHighlighter(self)
117 self._input_splitter = self._input_splitter_class(input_mode='block')
119 self._input_splitter = self._input_splitter_class(input_mode='cell')
118 120 self._kernel_manager = None
119 121 self._possible_kernel_restart = False
120 122 self._request_info = {}
@@ -236,6 +238,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
236 238 """ Reimplemented for auto-indentation.
237 239 """
238 240 super(FrontendWidget, self)._insert_continuation_prompt(cursor)
241 #print('SPACES:', self._input_splitter.indent_spaces) # dbg
239 242 spaces = self._input_splitter.indent_spaces
240 243 cursor.insertText('\t' * (spaces / self.tab_width))
241 244 cursor.insertText(' ' * (spaces % self.tab_width))
General Comments 0
You need to be logged in to leave comments. Login now