##// END OF EJS Templates
make calltips configurable in qtconsole...
MinRK -
Show More
@@ -1,617 +1,622 b''
1 1 from __future__ import print_function
2 2
3 3 # Standard library imports
4 4 from collections import namedtuple
5 5 import sys
6 6 import time
7 7
8 8 # System library imports
9 9 from pygments.lexers import PythonLexer
10 10 from IPython.external.qt import QtCore, QtGui
11 11
12 12 # Local imports
13 13 from IPython.core.inputsplitter import InputSplitter, transform_classic_prompt
14 14 from IPython.core.oinspect import call_tip
15 15 from IPython.frontend.qt.base_frontend_mixin import BaseFrontendMixin
16 16 from IPython.utils.traitlets import Bool, Instance
17 17 from bracket_matcher import BracketMatcher
18 18 from call_tip_widget import CallTipWidget
19 19 from completion_lexer import CompletionLexer
20 20 from history_console_widget import HistoryConsoleWidget
21 21 from pygments_highlighter import PygmentsHighlighter
22 22
23 23
24 24 class FrontendHighlighter(PygmentsHighlighter):
25 25 """ A PygmentsHighlighter that understands and ignores prompts.
26 26 """
27 27
28 28 def __init__(self, frontend):
29 29 super(FrontendHighlighter, self).__init__(frontend._control.document())
30 30 self._current_offset = 0
31 31 self._frontend = frontend
32 32 self.highlighting_on = False
33 33
34 34 def highlightBlock(self, string):
35 35 """ Highlight a block of text. Reimplemented to highlight selectively.
36 36 """
37 37 if not self.highlighting_on:
38 38 return
39 39
40 40 # The input to this function is a unicode string that may contain
41 41 # paragraph break characters, non-breaking spaces, etc. Here we acquire
42 42 # the string as plain text so we can compare it.
43 43 current_block = self.currentBlock()
44 44 string = self._frontend._get_block_plain_text(current_block)
45 45
46 46 # Decide whether to check for the regular or continuation prompt.
47 47 if current_block.contains(self._frontend._prompt_pos):
48 48 prompt = self._frontend._prompt
49 49 else:
50 50 prompt = self._frontend._continuation_prompt
51 51
52 52 # Only highlight if we can identify a prompt, but make sure not to
53 53 # highlight the prompt.
54 54 if string.startswith(prompt):
55 55 self._current_offset = len(prompt)
56 56 string = string[len(prompt):]
57 57 super(FrontendHighlighter, self).highlightBlock(string)
58 58
59 59 def rehighlightBlock(self, block):
60 60 """ Reimplemented to temporarily enable highlighting if disabled.
61 61 """
62 62 old = self.highlighting_on
63 63 self.highlighting_on = True
64 64 super(FrontendHighlighter, self).rehighlightBlock(block)
65 65 self.highlighting_on = old
66 66
67 67 def setFormat(self, start, count, format):
68 68 """ Reimplemented to highlight selectively.
69 69 """
70 70 start += self._current_offset
71 71 super(FrontendHighlighter, self).setFormat(start, count, format)
72 72
73 73
74 74 class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
75 75 """ A Qt frontend for a generic Python kernel.
76 76 """
77 77
78 enable_calltips = Bool(True, config=True,
79 help="Whether to draw information calltips on open-parentheses.")
80
78 81 # An option and corresponding signal for overriding the default kernel
79 82 # interrupt behavior.
80 83 custom_interrupt = Bool(False)
81 84 custom_interrupt_requested = QtCore.Signal()
82 85
83 86 # An option and corresponding signals for overriding the default kernel
84 87 # restart behavior.
85 88 custom_restart = Bool(False)
86 89 custom_restart_kernel_died = QtCore.Signal(float)
87 90 custom_restart_requested = QtCore.Signal()
88 91
89 92 # Emitted when a user visible 'execute_request' has been submitted to the
90 93 # kernel from the FrontendWidget. Contains the code to be executed.
91 94 executing = QtCore.Signal(object)
92 95
93 96 # Emitted when a user-visible 'execute_reply' has been received from the
94 97 # kernel and processed by the FrontendWidget. Contains the response message.
95 98 executed = QtCore.Signal(object)
96 99
97 100 # Emitted when an exit request has been received from the kernel.
98 101 exit_requested = QtCore.Signal()
99 102
100 103 # Protected class variables.
101 104 _CallTipRequest = namedtuple('_CallTipRequest', ['id', 'pos'])
102 105 _CompletionRequest = namedtuple('_CompletionRequest', ['id', 'pos'])
103 106 _ExecutionRequest = namedtuple('_ExecutionRequest', ['id', 'kind'])
104 107 _input_splitter_class = InputSplitter
105 108 _local_kernel = False
106 109 _highlighter = Instance(FrontendHighlighter)
107 110
108 111 #---------------------------------------------------------------------------
109 112 # 'object' interface
110 113 #---------------------------------------------------------------------------
111 114
112 115 def __init__(self, *args, **kw):
113 116 super(FrontendWidget, self).__init__(*args, **kw)
114 117
115 118 # FrontendWidget protected variables.
116 119 self._bracket_matcher = BracketMatcher(self._control)
117 120 self._call_tip_widget = CallTipWidget(self._control)
118 121 self._completion_lexer = CompletionLexer(PythonLexer())
119 122 self._copy_raw_action = QtGui.QAction('Copy (Raw Text)', None)
120 123 self._hidden = False
121 124 self._highlighter = FrontendHighlighter(self)
122 125 self._input_splitter = self._input_splitter_class(input_mode='cell')
123 126 self._kernel_manager = None
124 127 self._request_info = {}
125 128
126 129 # Configure the ConsoleWidget.
127 130 self.tab_width = 4
128 131 self._set_continuation_prompt('... ')
129 132
130 133 # Configure the CallTipWidget.
131 134 self._call_tip_widget.setFont(self.font)
132 135 self.font_changed.connect(self._call_tip_widget.setFont)
133 136
134 137 # Configure actions.
135 138 action = self._copy_raw_action
136 139 key = QtCore.Qt.CTRL | QtCore.Qt.SHIFT | QtCore.Qt.Key_C
137 140 action.setEnabled(False)
138 141 action.setShortcut(QtGui.QKeySequence(key))
139 142 action.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
140 143 action.triggered.connect(self.copy_raw)
141 144 self.copy_available.connect(action.setEnabled)
142 145 self.addAction(action)
143 146
144 147 # Connect signal handlers.
145 148 document = self._control.document()
146 149 document.contentsChange.connect(self._document_contents_change)
147 150
148 151 # Set flag for whether we are connected via localhost.
149 152 self._local_kernel = kw.get('local_kernel',
150 153 FrontendWidget._local_kernel)
151 154
152 155 #---------------------------------------------------------------------------
153 156 # 'ConsoleWidget' public interface
154 157 #---------------------------------------------------------------------------
155 158
156 159 def copy(self):
157 160 """ Copy the currently selected text to the clipboard, removing prompts.
158 161 """
159 162 text = self._control.textCursor().selection().toPlainText()
160 163 if text:
161 164 lines = map(transform_classic_prompt, text.splitlines())
162 165 text = '\n'.join(lines)
163 166 QtGui.QApplication.clipboard().setText(text)
164 167
165 168 #---------------------------------------------------------------------------
166 169 # 'ConsoleWidget' abstract interface
167 170 #---------------------------------------------------------------------------
168 171
169 172 def _is_complete(self, source, interactive):
170 173 """ Returns whether 'source' can be completely processed and a new
171 174 prompt created. When triggered by an Enter/Return key press,
172 175 'interactive' is True; otherwise, it is False.
173 176 """
174 177 complete = self._input_splitter.push(source)
175 178 if interactive:
176 179 complete = not self._input_splitter.push_accepts_more()
177 180 return complete
178 181
179 182 def _execute(self, source, hidden):
180 183 """ Execute 'source'. If 'hidden', do not show any output.
181 184
182 185 See parent class :meth:`execute` docstring for full details.
183 186 """
184 187 msg_id = self.kernel_manager.shell_channel.execute(source, hidden)
185 188 self._request_info['execute'] = self._ExecutionRequest(msg_id, 'user')
186 189 self._hidden = hidden
187 190 if not hidden:
188 191 self.executing.emit(source)
189 192
190 193 def _prompt_started_hook(self):
191 194 """ Called immediately after a new prompt is displayed.
192 195 """
193 196 if not self._reading:
194 197 self._highlighter.highlighting_on = True
195 198
196 199 def _prompt_finished_hook(self):
197 200 """ Called immediately after a prompt is finished, i.e. when some input
198 201 will be processed and a new prompt displayed.
199 202 """
200 203 # Flush all state from the input splitter so the next round of
201 204 # reading input starts with a clean buffer.
202 205 self._input_splitter.reset()
203 206
204 207 if not self._reading:
205 208 self._highlighter.highlighting_on = False
206 209
207 210 def _tab_pressed(self):
208 211 """ Called when the tab key is pressed. Returns whether to continue
209 212 processing the event.
210 213 """
211 214 # Perform tab completion if:
212 215 # 1) The cursor is in the input buffer.
213 216 # 2) There is a non-whitespace character before the cursor.
214 217 text = self._get_input_buffer_cursor_line()
215 218 if text is None:
216 219 return False
217 220 complete = bool(text[:self._get_input_buffer_cursor_column()].strip())
218 221 if complete:
219 222 self._complete()
220 223 return not complete
221 224
222 225 #---------------------------------------------------------------------------
223 226 # 'ConsoleWidget' protected interface
224 227 #---------------------------------------------------------------------------
225 228
226 229 def _context_menu_make(self, pos):
227 230 """ Reimplemented to add an action for raw copy.
228 231 """
229 232 menu = super(FrontendWidget, self)._context_menu_make(pos)
230 233 for before_action in menu.actions():
231 234 if before_action.shortcut().matches(QtGui.QKeySequence.Paste) == \
232 235 QtGui.QKeySequence.ExactMatch:
233 236 menu.insertAction(before_action, self._copy_raw_action)
234 237 break
235 238 return menu
236 239
237 240 def _event_filter_console_keypress(self, event):
238 241 """ Reimplemented for execution interruption and smart backspace.
239 242 """
240 243 key = event.key()
241 244 if self._control_key_down(event.modifiers(), include_command=False):
242 245
243 246 if key == QtCore.Qt.Key_C and self._executing:
244 247 self.interrupt_kernel()
245 248 return True
246 249
247 250 elif key == QtCore.Qt.Key_Period:
248 251 message = 'Are you sure you want to restart the kernel?'
249 252 self.restart_kernel(message, now=False)
250 253 return True
251 254
252 255 elif not event.modifiers() & QtCore.Qt.AltModifier:
253 256
254 257 # Smart backspace: remove four characters in one backspace if:
255 258 # 1) everything left of the cursor is whitespace
256 259 # 2) the four characters immediately left of the cursor are spaces
257 260 if key == QtCore.Qt.Key_Backspace:
258 261 col = self._get_input_buffer_cursor_column()
259 262 cursor = self._control.textCursor()
260 263 if col > 3 and not cursor.hasSelection():
261 264 text = self._get_input_buffer_cursor_line()[:col]
262 265 if text.endswith(' ') and not text.strip():
263 266 cursor.movePosition(QtGui.QTextCursor.Left,
264 267 QtGui.QTextCursor.KeepAnchor, 4)
265 268 cursor.removeSelectedText()
266 269 return True
267 270
268 271 return super(FrontendWidget, self)._event_filter_console_keypress(event)
269 272
270 273 def _insert_continuation_prompt(self, cursor):
271 274 """ Reimplemented for auto-indentation.
272 275 """
273 276 super(FrontendWidget, self)._insert_continuation_prompt(cursor)
274 277 cursor.insertText(' ' * self._input_splitter.indent_spaces)
275 278
276 279 #---------------------------------------------------------------------------
277 280 # 'BaseFrontendMixin' abstract interface
278 281 #---------------------------------------------------------------------------
279 282
280 283 def _handle_complete_reply(self, rep):
281 284 """ Handle replies for tab completion.
282 285 """
283 286 cursor = self._get_cursor()
284 287 info = self._request_info.get('complete')
285 288 if info and info.id == rep['parent_header']['msg_id'] and \
286 289 info.pos == cursor.position():
287 290 text = '.'.join(self._get_context())
288 291 cursor.movePosition(QtGui.QTextCursor.Left, n=len(text))
289 292 self._complete_with_items(cursor, rep['content']['matches'])
290 293
291 294 def _handle_execute_reply(self, msg):
292 295 """ Handles replies for code execution.
293 296 """
294 297 info = self._request_info.get('execute')
295 298 if info and info.id == msg['parent_header']['msg_id'] and \
296 299 info.kind == 'user' and not self._hidden:
297 300 # Make sure that all output from the SUB channel has been processed
298 301 # before writing a new prompt.
299 302 self.kernel_manager.sub_channel.flush()
300 303
301 304 # Reset the ANSI style information to prevent bad text in stdout
302 305 # from messing up our colors. We're not a true terminal so we're
303 306 # allowed to do this.
304 307 if self.ansi_codes:
305 308 self._ansi_processor.reset_sgr()
306 309
307 310 content = msg['content']
308 311 status = content['status']
309 312 if status == 'ok':
310 313 self._process_execute_ok(msg)
311 314 elif status == 'error':
312 315 self._process_execute_error(msg)
313 316 elif status == 'abort':
314 317 self._process_execute_abort(msg)
315 318
316 319 self._show_interpreter_prompt_for_reply(msg)
317 320 self.executed.emit(msg)
318 321
319 322 def _handle_input_request(self, msg):
320 323 """ Handle requests for raw_input.
321 324 """
322 325 if self._hidden:
323 326 raise RuntimeError('Request for raw input during hidden execution.')
324 327
325 328 # Make sure that all output from the SUB channel has been processed
326 329 # before entering readline mode.
327 330 self.kernel_manager.sub_channel.flush()
328 331
329 332 def callback(line):
330 333 self.kernel_manager.stdin_channel.input(line)
331 334 self._readline(msg['content']['prompt'], callback=callback)
332 335
333 336 def _handle_kernel_died(self, since_last_heartbeat):
334 337 """ Handle the kernel's death by asking if the user wants to restart.
335 338 """
336 339 if self.custom_restart:
337 340 self.custom_restart_kernel_died.emit(since_last_heartbeat)
338 341 else:
339 342 message = 'The kernel heartbeat has been inactive for %.2f ' \
340 343 'seconds. Do you want to restart the kernel? You may ' \
341 344 'first want to check the network connection.' % \
342 345 since_last_heartbeat
343 346 self.restart_kernel(message, now=True)
344 347
345 348 def _handle_object_info_reply(self, rep):
346 349 """ Handle replies for call tips.
347 350 """
348 351 cursor = self._get_cursor()
349 352 info = self._request_info.get('call_tip')
350 353 if info and info.id == rep['parent_header']['msg_id'] and \
351 354 info.pos == cursor.position():
352 355 # Get the information for a call tip. For now we format the call
353 356 # line as string, later we can pass False to format_call and
354 357 # syntax-highlight it ourselves for nicer formatting in the
355 358 # calltip.
356 359 content = rep['content']
357 360 # if this is from pykernel, 'docstring' will be the only key
358 361 if content.get('ismagic', False):
359 362 # Don't generate a call-tip for magics. Ideally, we should
360 363 # generate a tooltip, but not on ( like we do for actual
361 364 # callables.
362 365 call_info, doc = None, None
363 366 else:
364 367 call_info, doc = call_tip(content, format_call=True)
365 368 if call_info or doc:
366 369 self._call_tip_widget.show_call_info(call_info, doc)
367 370
368 371 def _handle_pyout(self, msg):
369 372 """ Handle display hook output.
370 373 """
371 374 if not self._hidden and self._is_from_this_session(msg):
372 375 text = msg['content']['data']
373 376 self._append_plain_text(text + '\n', before_prompt=True)
374 377
375 378 def _handle_stream(self, msg):
376 379 """ Handle stdout, stderr, and stdin.
377 380 """
378 381 if not self._hidden and self._is_from_this_session(msg):
379 382 # Most consoles treat tabs as being 8 space characters. Convert tabs
380 383 # to spaces so that output looks as expected regardless of this
381 384 # widget's tab width.
382 385 text = msg['content']['data'].expandtabs(8)
383 386
384 387 self._append_plain_text(text, before_prompt=True)
385 388 self._control.moveCursor(QtGui.QTextCursor.End)
386 389
387 390 def _handle_shutdown_reply(self, msg):
388 391 """ Handle shutdown signal, only if from other console.
389 392 """
390 393 if not self._hidden and not self._is_from_this_session(msg):
391 394 if self._local_kernel:
392 395 if not msg['content']['restart']:
393 396 sys.exit(0)
394 397 else:
395 398 # we just got notified of a restart!
396 399 time.sleep(0.25) # wait 1/4 sec to reset
397 400 # lest the request for a new prompt
398 401 # goes to the old kernel
399 402 self.reset()
400 403 else: # remote kernel, prompt on Kernel shutdown/reset
401 404 title = self.window().windowTitle()
402 405 if not msg['content']['restart']:
403 406 reply = QtGui.QMessageBox.question(self, title,
404 407 "Kernel has been shutdown permanently. "
405 408 "Close the Console?",
406 409 QtGui.QMessageBox.Yes,QtGui.QMessageBox.No)
407 410 if reply == QtGui.QMessageBox.Yes:
408 411 sys.exit(0)
409 412 else:
410 413 reply = QtGui.QMessageBox.question(self, title,
411 414 "Kernel has been reset. Clear the Console?",
412 415 QtGui.QMessageBox.Yes,QtGui.QMessageBox.No)
413 416 if reply == QtGui.QMessageBox.Yes:
414 417 time.sleep(0.25) # wait 1/4 sec to reset
415 418 # lest the request for a new prompt
416 419 # goes to the old kernel
417 420 self.reset()
418 421
419 422 def _started_channels(self):
420 423 """ Called when the KernelManager channels have started listening or
421 424 when the frontend is assigned an already listening KernelManager.
422 425 """
423 426 self.reset()
424 427
425 428 #---------------------------------------------------------------------------
426 429 # 'FrontendWidget' public interface
427 430 #---------------------------------------------------------------------------
428 431
429 432 def copy_raw(self):
430 433 """ Copy the currently selected text to the clipboard without attempting
431 434 to remove prompts or otherwise alter the text.
432 435 """
433 436 self._control.copy()
434 437
435 438 def execute_file(self, path, hidden=False):
436 439 """ Attempts to execute file with 'path'. If 'hidden', no output is
437 440 shown.
438 441 """
439 442 self.execute('execfile(%r)' % path, hidden=hidden)
440 443
441 444 def interrupt_kernel(self):
442 445 """ Attempts to interrupt the running kernel.
443 446 """
444 447 if self.custom_interrupt:
445 448 self.custom_interrupt_requested.emit()
446 449 elif self.kernel_manager.has_kernel:
447 450 self.kernel_manager.interrupt_kernel()
448 451 else:
449 452 self._append_plain_text('Kernel process is either remote or '
450 453 'unspecified. Cannot interrupt.\n')
451 454
452 455 def reset(self):
453 456 """ Resets the widget to its initial state. Similar to ``clear``, but
454 457 also re-writes the banner and aborts execution if necessary.
455 458 """
456 459 if self._executing:
457 460 self._executing = False
458 461 self._request_info['execute'] = None
459 462 self._reading = False
460 463 self._highlighter.highlighting_on = False
461 464
462 465 self._control.clear()
463 466 self._append_plain_text(self._get_banner())
464 467 self._show_interpreter_prompt()
465 468
466 469 def restart_kernel(self, message, now=False):
467 470 """ Attempts to restart the running kernel.
468 471 """
469 472 # FIXME: now should be configurable via a checkbox in the dialog. Right
470 473 # now at least the heartbeat path sets it to True and the manual restart
471 474 # to False. But those should just be the pre-selected states of a
472 475 # checkbox that the user could override if so desired. But I don't know
473 476 # enough Qt to go implementing the checkbox now.
474 477
475 478 if self.custom_restart:
476 479 self.custom_restart_requested.emit()
477 480
478 481 elif self.kernel_manager.has_kernel:
479 482 # Pause the heart beat channel to prevent further warnings.
480 483 self.kernel_manager.hb_channel.pause()
481 484
482 485 # Prompt the user to restart the kernel. Un-pause the heartbeat if
483 486 # they decline. (If they accept, the heartbeat will be un-paused
484 487 # automatically when the kernel is restarted.)
485 488 buttons = QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
486 489 result = QtGui.QMessageBox.question(self, 'Restart kernel?',
487 490 message, buttons)
488 491 if result == QtGui.QMessageBox.Yes:
489 492 try:
490 493 self.kernel_manager.restart_kernel(now=now)
491 494 except RuntimeError:
492 495 self._append_plain_text('Kernel started externally. '
493 496 'Cannot restart.\n')
494 497 else:
495 498 self.reset()
496 499 else:
497 500 self.kernel_manager.hb_channel.unpause()
498 501
499 502 else:
500 503 self._append_plain_text('Kernel process is either remote or '
501 504 'unspecified. Cannot restart.\n')
502 505
503 506 #---------------------------------------------------------------------------
504 507 # 'FrontendWidget' protected interface
505 508 #---------------------------------------------------------------------------
506 509
507 510 def _call_tip(self):
508 511 """ Shows a call tip, if appropriate, at the current cursor location.
509 512 """
510 513 # Decide if it makes sense to show a call tip
514 if not self.enable_calltips:
515 return False
511 516 cursor = self._get_cursor()
512 517 cursor.movePosition(QtGui.QTextCursor.Left)
513 518 if cursor.document().characterAt(cursor.position()) != '(':
514 519 return False
515 520 context = self._get_context(cursor)
516 521 if not context:
517 522 return False
518 523
519 524 # Send the metadata request to the kernel
520 525 name = '.'.join(context)
521 526 msg_id = self.kernel_manager.shell_channel.object_info(name)
522 527 pos = self._get_cursor().position()
523 528 self._request_info['call_tip'] = self._CallTipRequest(msg_id, pos)
524 529 return True
525 530
526 531 def _complete(self):
527 532 """ Performs completion at the current cursor location.
528 533 """
529 534 context = self._get_context()
530 535 if context:
531 536 # Send the completion request to the kernel
532 537 msg_id = self.kernel_manager.shell_channel.complete(
533 538 '.'.join(context), # text
534 539 self._get_input_buffer_cursor_line(), # line
535 540 self._get_input_buffer_cursor_column(), # cursor_pos
536 541 self.input_buffer) # block
537 542 pos = self._get_cursor().position()
538 543 info = self._CompletionRequest(msg_id, pos)
539 544 self._request_info['complete'] = info
540 545
541 546 def _get_banner(self):
542 547 """ Gets a banner to display at the beginning of a session.
543 548 """
544 549 banner = 'Python %s on %s\nType "help", "copyright", "credits" or ' \
545 550 '"license" for more information.'
546 551 return banner % (sys.version, sys.platform)
547 552
548 553 def _get_context(self, cursor=None):
549 554 """ Gets the context for the specified cursor (or the current cursor
550 555 if none is specified).
551 556 """
552 557 if cursor is None:
553 558 cursor = self._get_cursor()
554 559 cursor.movePosition(QtGui.QTextCursor.StartOfBlock,
555 560 QtGui.QTextCursor.KeepAnchor)
556 561 text = cursor.selection().toPlainText()
557 562 return self._completion_lexer.get_context(text)
558 563
559 564 def _process_execute_abort(self, msg):
560 565 """ Process a reply for an aborted execution request.
561 566 """
562 567 self._append_plain_text("ERROR: execution aborted\n")
563 568
564 569 def _process_execute_error(self, msg):
565 570 """ Process a reply for an execution request that resulted in an error.
566 571 """
567 572 content = msg['content']
568 573 # If a SystemExit is passed along, this means exit() was called - also
569 574 # all the ipython %exit magic syntax of '-k' to be used to keep
570 575 # the kernel running
571 576 if content['ename']=='SystemExit':
572 577 keepkernel = content['evalue']=='-k' or content['evalue']=='True'
573 578 self._keep_kernel_on_exit = keepkernel
574 579 self.exit_requested.emit()
575 580 else:
576 581 traceback = ''.join(content['traceback'])
577 582 self._append_plain_text(traceback)
578 583
579 584 def _process_execute_ok(self, msg):
580 585 """ Process a reply for a successful execution equest.
581 586 """
582 587 payload = msg['content']['payload']
583 588 for item in payload:
584 589 if not self._process_execute_payload(item):
585 590 warning = 'Warning: received unknown payload of type %s'
586 591 print(warning % repr(item['source']))
587 592
588 593 def _process_execute_payload(self, item):
589 594 """ Process a single payload item from the list of payload items in an
590 595 execution reply. Returns whether the payload was handled.
591 596 """
592 597 # The basic FrontendWidget doesn't handle payloads, as they are a
593 598 # mechanism for going beyond the standard Python interpreter model.
594 599 return False
595 600
596 601 def _show_interpreter_prompt(self):
597 602 """ Shows a prompt for the interpreter.
598 603 """
599 604 self._show_prompt('>>> ')
600 605
601 606 def _show_interpreter_prompt_for_reply(self, msg):
602 607 """ Shows a prompt for the interpreter given an 'execute_reply' message.
603 608 """
604 609 self._show_interpreter_prompt()
605 610
606 611 #------ Signal handlers ----------------------------------------------------
607 612
608 613 def _document_contents_change(self, position, removed, added):
609 614 """ Called whenever the document's content changes. Display a call tip
610 615 if appropriate.
611 616 """
612 617 # Calculate where the cursor should be *after* the change:
613 618 position += added
614 619
615 620 document = self._control.document()
616 621 if position == self._get_cursor().position():
617 622 self._call_tip()
General Comments 0
You need to be logged in to leave comments. Login now