Show More
@@ -133,12 +133,15 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
133 | def __init__(self, parent=None): |
|
133 | def __init__(self, parent=None): | |
134 | QtGui.QPlainTextEdit.__init__(self, parent) |
|
134 | QtGui.QPlainTextEdit.__init__(self, parent) | |
135 |
|
135 | |||
136 | # Initialize protected variables. |
|
136 | # Initialize protected variables. Some variables contain useful state | |
|
137 | # information for subclasses; they should be considered read-only. | |||
137 | self._ansi_processor = QtAnsiCodeProcessor() |
|
138 | self._ansi_processor = QtAnsiCodeProcessor() | |
138 | self._completion_widget = CompletionWidget(self) |
|
139 | self._completion_widget = CompletionWidget(self) | |
139 | self._continuation_prompt = '> ' |
|
140 | self._continuation_prompt = '> ' | |
|
141 | self._continuation_prompt_html = None | |||
140 | self._executing = False |
|
142 | self._executing = False | |
141 | self._prompt = '' |
|
143 | self._prompt = '' | |
|
144 | self._prompt_html = None | |||
142 | self._prompt_pos = 0 |
|
145 | self._prompt_pos = 0 | |
143 | self._reading = False |
|
146 | self._reading = False | |
144 | self._reading_callback = None |
|
147 | self._reading_callback = None | |
@@ -343,14 +346,34 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
343 | # 'QPlainTextEdit' interface |
|
346 | # 'QPlainTextEdit' interface | |
344 | #-------------------------------------------------------------------------- |
|
347 | #-------------------------------------------------------------------------- | |
345 |
|
348 | |||
|
349 | def appendHtml(self, html): | |||
|
350 | """ Reimplemented to not append HTML as a new paragraph, which doesn't | |||
|
351 | make sense for a console widget. | |||
|
352 | """ | |||
|
353 | cursor = self._get_end_cursor() | |||
|
354 | cursor.insertHtml(html) | |||
|
355 | ||||
|
356 | # After appending HTML, the text document "remembers" the current | |||
|
357 | # formatting, which means that subsequent calls to 'appendPlainText' | |||
|
358 | # will be formatted similarly, a behavior that we do not want. To | |||
|
359 | # prevent this, we make sure that the last character has no formatting. | |||
|
360 | cursor.movePosition(QtGui.QTextCursor.Left, | |||
|
361 | QtGui.QTextCursor.KeepAnchor) | |||
|
362 | if cursor.selection().toPlainText().trimmed().isEmpty(): | |||
|
363 | # If the last character is whitespace, it doesn't matter how it's | |||
|
364 | # formatted, so just clear the formatting. | |||
|
365 | cursor.setCharFormat(QtGui.QTextCharFormat()) | |||
|
366 | else: | |||
|
367 | # Otherwise, add an unformatted space. | |||
|
368 | cursor.movePosition(QtGui.QTextCursor.Right) | |||
|
369 | cursor.insertText(' ', QtGui.QTextCharFormat()) | |||
|
370 | ||||
346 | def appendPlainText(self, text): |
|
371 | def appendPlainText(self, text): | |
347 | """ Reimplemented to not append text as a new paragraph, which doesn't |
|
372 | """ Reimplemented to not append text as a new paragraph, which doesn't | |
348 | make sense for a console widget. Also, if enabled, handle ANSI |
|
373 | make sense for a console widget. Also, if enabled, handle ANSI | |
349 | codes. |
|
374 | codes. | |
350 | """ |
|
375 | """ | |
351 |
cursor = self. |
|
376 | cursor = self._get_end_cursor() | |
352 | cursor.movePosition(QtGui.QTextCursor.End) |
|
|||
353 |
|
||||
354 | if self.ansi_codes: |
|
377 | if self.ansi_codes: | |
355 | format = QtGui.QTextCharFormat() |
|
378 | format = QtGui.QTextCharFormat() | |
356 | previous_end = 0 |
|
379 | previous_end = 0 | |
@@ -365,18 +388,15 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
365 | cursor.insertText(text) |
|
388 | cursor.insertText(text) | |
366 |
|
389 | |||
367 | def clear(self, keep_input=False): |
|
390 | def clear(self, keep_input=False): | |
368 |
""" Reimplemented to |
|
391 | """ Reimplemented to write a new prompt. If 'keep_input' is set, | |
369 |
|
|
392 | restores the old input buffer when the new prompt is written. | |
370 | prompt is written. |
|
|||
371 | """ |
|
393 | """ | |
372 | QtGui.QPlainTextEdit.clear(self) |
|
394 | QtGui.QPlainTextEdit.clear(self) | |
373 | input_buffer = '' |
|
395 | if keep_input: | |
374 | if self._reading: |
|
|||
375 | self._reading = False |
|
|||
376 | elif keep_input: |
|
|||
377 | input_buffer = self.input_buffer |
|
396 | input_buffer = self.input_buffer | |
378 | self._show_prompt() |
|
397 | self._show_prompt() | |
379 | self.input_buffer = input_buffer |
|
398 | if keep_input: | |
|
399 | self.input_buffer = input_buffer | |||
380 |
|
400 | |||
381 | def paste(self): |
|
401 | def paste(self): | |
382 | """ Reimplemented to ensure that text is pasted in the editing region. |
|
402 | """ Reimplemented to ensure that text is pasted in the editing region. | |
@@ -463,9 +483,6 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
463 |
|
483 | |||
464 | cursor = self._get_end_cursor() |
|
484 | cursor = self._get_end_cursor() | |
465 | cursor.setPosition(self._prompt_pos, QtGui.QTextCursor.KeepAnchor) |
|
485 | cursor.setPosition(self._prompt_pos, QtGui.QTextCursor.KeepAnchor) | |
466 |
|
||||
467 | # Use QTextDocumentFragment intermediate object because it strips |
|
|||
468 | # out the Unicode line break characters that Qt insists on inserting. |
|
|||
469 | input_buffer = str(cursor.selection().toPlainText()) |
|
486 | input_buffer = str(cursor.selection().toPlainText()) | |
470 |
|
487 | |||
471 | # Strip out continuation prompts. |
|
488 | # Strip out continuation prompts. | |
@@ -496,7 +513,7 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
496 | return None |
|
513 | return None | |
497 | cursor = self.textCursor() |
|
514 | cursor = self.textCursor() | |
498 | if cursor.position() >= self._prompt_pos: |
|
515 | if cursor.position() >= self._prompt_pos: | |
499 |
text = s |
|
516 | text = self._get_block_plain_text(cursor.block()) | |
500 | if cursor.blockNumber() == self._get_prompt_cursor().blockNumber(): |
|
517 | if cursor.blockNumber() == self._get_prompt_cursor().blockNumber(): | |
501 | return text[len(self._prompt):] |
|
518 | return text[len(self._prompt):] | |
502 | else: |
|
519 | else: | |
@@ -581,6 +598,27 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
581 | # 'ConsoleWidget' protected interface |
|
598 | # 'ConsoleWidget' protected interface | |
582 | #-------------------------------------------------------------------------- |
|
599 | #-------------------------------------------------------------------------- | |
583 |
|
600 | |||
|
601 | def _append_html_fetching_plain_text(self, html): | |||
|
602 | """ Appends 'html', then returns the plain text version of it. | |||
|
603 | """ | |||
|
604 | anchor = self._get_end_cursor().position() | |||
|
605 | self.appendHtml(html) | |||
|
606 | cursor = self._get_end_cursor() | |||
|
607 | cursor.setPosition(anchor, QtGui.QTextCursor.KeepAnchor) | |||
|
608 | return str(cursor.selection().toPlainText()) | |||
|
609 | ||||
|
610 | def _append_plain_text_keeping_prompt(self, text): | |||
|
611 | """ Writes 'text' after the current prompt, then restores the old prompt | |||
|
612 | with its old input buffer. | |||
|
613 | """ | |||
|
614 | input_buffer = self.input_buffer | |||
|
615 | self.appendPlainText('\n') | |||
|
616 | self._prompt_finished() | |||
|
617 | ||||
|
618 | self.appendPlainText(text) | |||
|
619 | self._show_prompt() | |||
|
620 | self.input_buffer = input_buffer | |||
|
621 | ||||
584 | def _control_down(self, modifiers): |
|
622 | def _control_down(self, modifiers): | |
585 | """ Given a KeyboardModifiers flags object, return whether the Control |
|
623 | """ Given a KeyboardModifiers flags object, return whether the Control | |
586 | key is down (on Mac OS, treat the Command key as a synonym for |
|
624 | key is down (on Mac OS, treat the Command key as a synonym for | |
@@ -607,7 +645,16 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
607 | self._completion_widget.show_items(cursor, items) |
|
645 | self._completion_widget.show_items(cursor, items) | |
608 | else: |
|
646 | else: | |
609 | text = '\n'.join(items) + '\n' |
|
647 | text = '\n'.join(items) + '\n' | |
610 |
self._ |
|
648 | self._append_plain_text_keeping_prompt(text) | |
|
649 | ||||
|
650 | def _get_block_plain_text(self, block): | |||
|
651 | """ Given a QTextBlock, return its unformatted text. | |||
|
652 | """ | |||
|
653 | cursor = QtGui.QTextCursor(block) | |||
|
654 | cursor.movePosition(QtGui.QTextCursor.StartOfBlock) | |||
|
655 | cursor.movePosition(QtGui.QTextCursor.EndOfBlock, | |||
|
656 | QtGui.QTextCursor.KeepAnchor) | |||
|
657 | return str(cursor.selection().toPlainText()) | |||
611 |
|
658 | |||
612 | def _get_end_cursor(self): |
|
659 | def _get_end_cursor(self): | |
613 | """ Convenience method that returns a cursor for the last character. |
|
660 | """ Convenience method that returns a cursor for the last character. | |
@@ -728,6 +775,31 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
728 | self._reading_callback = lambda: \ |
|
775 | self._reading_callback = lambda: \ | |
729 | callback(self.input_buffer.rstrip('\n')) |
|
776 | callback(self.input_buffer.rstrip('\n')) | |
730 |
|
777 | |||
|
778 | def _reset(self): | |||
|
779 | """ Clears the console and resets internal state variables. | |||
|
780 | """ | |||
|
781 | QtGui.QPlainTextEdit.clear(self) | |||
|
782 | self._executing = self._reading = False | |||
|
783 | ||||
|
784 | def _set_continuation_prompt(self, prompt, html=False): | |||
|
785 | """ Sets the continuation prompt. | |||
|
786 | ||||
|
787 | Parameters | |||
|
788 | ---------- | |||
|
789 | prompt : str | |||
|
790 | The prompt to show when more input is needed. | |||
|
791 | ||||
|
792 | html : bool, optional (default False) | |||
|
793 | If set, the prompt will be inserted as formatted HTML. Otherwise, | |||
|
794 | the prompt will be treated as plain text, though ANSI color codes | |||
|
795 | will be handled. | |||
|
796 | """ | |||
|
797 | if html: | |||
|
798 | self._continuation_prompt_html = prompt | |||
|
799 | else: | |||
|
800 | self._continuation_prompt = prompt | |||
|
801 | self._continuation_prompt_html = None | |||
|
802 | ||||
731 | def _set_position(self, position): |
|
803 | def _set_position(self, position): | |
732 | """ Convenience method to set the position of the cursor. |
|
804 | """ Convenience method to set the position of the cursor. | |
733 | """ |
|
805 | """ | |
@@ -740,7 +812,7 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
740 | """ |
|
812 | """ | |
741 | self.setTextCursor(self._get_selection_cursor(start, end)) |
|
813 | self.setTextCursor(self._get_selection_cursor(start, end)) | |
742 |
|
814 | |||
743 | def _show_prompt(self, prompt=None, newline=True): |
|
815 | def _show_prompt(self, prompt=None, html=False, newline=True): | |
744 | """ Writes a new prompt at the end of the buffer. |
|
816 | """ Writes a new prompt at the end of the buffer. | |
745 |
|
817 | |||
746 | Parameters |
|
818 | Parameters | |
@@ -748,10 +820,16 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
748 | prompt : str, optional |
|
820 | prompt : str, optional | |
749 | The prompt to show. If not specified, the previous prompt is used. |
|
821 | The prompt to show. If not specified, the previous prompt is used. | |
750 |
|
822 | |||
|
823 | html : bool, optional (default False) | |||
|
824 | Only relevant when a prompt is specified. If set, the prompt will | |||
|
825 | be inserted as formatted HTML. Otherwise, the prompt will be treated | |||
|
826 | as plain text, though ANSI color codes will be handled. | |||
|
827 | ||||
751 | newline : bool, optional (default True) |
|
828 | newline : bool, optional (default True) | |
752 | If set, a new line will be written before showing the prompt if |
|
829 | If set, a new line will be written before showing the prompt if | |
753 | there is not already a newline at the end of the buffer. |
|
830 | there is not already a newline at the end of the buffer. | |
754 | """ |
|
831 | """ | |
|
832 | # Insert a preliminary newline, if necessary. | |||
755 | if newline: |
|
833 | if newline: | |
756 | cursor = self._get_end_cursor() |
|
834 | cursor = self._get_end_cursor() | |
757 | if cursor.position() > 0: |
|
835 | if cursor.position() > 0: | |
@@ -760,9 +838,20 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
760 | if str(cursor.selection().toPlainText()) != '\n': |
|
838 | if str(cursor.selection().toPlainText()) != '\n': | |
761 | self.appendPlainText('\n') |
|
839 | self.appendPlainText('\n') | |
762 |
|
840 | |||
763 | if prompt is not None: |
|
841 | # Write the prompt. | |
764 |
|
|
842 | if prompt is None: | |
765 | self.appendPlainText(self._prompt) |
|
843 | if self._prompt_html is None: | |
|
844 | self.appendPlainText(self._prompt) | |||
|
845 | else: | |||
|
846 | self.appendHtml(self._prompt_html) | |||
|
847 | else: | |||
|
848 | if html: | |||
|
849 | self._prompt = self._append_html_fetching_plain_text(prompt) | |||
|
850 | self._prompt_html = prompt | |||
|
851 | else: | |||
|
852 | self.appendPlainText(prompt) | |||
|
853 | self._prompt = prompt | |||
|
854 | self._prompt_html = None | |||
766 |
|
855 | |||
767 | self._prompt_pos = self._get_end_cursor().position() |
|
856 | self._prompt_pos = self._get_end_cursor().position() | |
768 | self._prompt_started() |
|
857 | self._prompt_started() | |
@@ -770,20 +859,13 b' class ConsoleWidget(QtGui.QPlainTextEdit):' | |||||
770 | def _show_continuation_prompt(self): |
|
859 | def _show_continuation_prompt(self): | |
771 | """ Writes a new continuation prompt at the end of the buffer. |
|
860 | """ Writes a new continuation prompt at the end of the buffer. | |
772 | """ |
|
861 | """ | |
773 |
self. |
|
862 | if self._continuation_prompt_html is None: | |
774 | self._prompt_started() |
|
863 | self.appendPlainText(self._continuation_prompt) | |
775 |
|
864 | else: | ||
776 | def _write_text_keeping_prompt(self, text): |
|
865 | self._continuation_prompt = self._append_html_fetching_plain_text( | |
777 | """ Writes 'text' after the current prompt, then restores the old prompt |
|
866 | self._continuation_prompt_html) | |
778 | with its old input buffer. |
|
|||
779 | """ |
|
|||
780 | input_buffer = self.input_buffer |
|
|||
781 | self.appendPlainText('\n') |
|
|||
782 | self._prompt_finished() |
|
|||
783 |
|
867 | |||
784 | self.appendPlainText(text) |
|
868 | self._prompt_started() | |
785 | self._show_prompt() |
|
|||
786 | self.input_buffer = input_buffer |
|
|||
787 |
|
869 | |||
788 | def _in_buffer(self, position): |
|
870 | def _in_buffer(self, position): | |
789 | """ Returns whether the given position is inside the editing region. |
|
871 | """ Returns whether the given position is inside the editing region. |
@@ -16,12 +16,12 b' from pygments_highlighter import PygmentsHighlighter' | |||||
16 |
|
16 | |||
17 |
|
17 | |||
18 | class FrontendHighlighter(PygmentsHighlighter): |
|
18 | class FrontendHighlighter(PygmentsHighlighter): | |
19 |
""" A Py |
|
19 | """ A PygmentsHighlighter that can be turned on and off and that ignores | |
20 | knows about continuation prompts. |
|
20 | prompts. | |
21 | """ |
|
21 | """ | |
22 |
|
22 | |||
23 | def __init__(self, frontend): |
|
23 | def __init__(self, frontend): | |
24 |
|
|
24 | super(FrontendHighlighter, self).__init__(frontend.document()) | |
25 | self._current_offset = 0 |
|
25 | self._current_offset = 0 | |
26 | self._frontend = frontend |
|
26 | self._frontend = frontend | |
27 | self.highlighting_on = False |
|
27 | self.highlighting_on = False | |
@@ -29,17 +29,32 b' class FrontendHighlighter(PygmentsHighlighter):' | |||||
29 | def highlightBlock(self, qstring): |
|
29 | def highlightBlock(self, qstring): | |
30 | """ Highlight a block of text. Reimplemented to highlight selectively. |
|
30 | """ Highlight a block of text. Reimplemented to highlight selectively. | |
31 | """ |
|
31 | """ | |
32 | if self.highlighting_on: |
|
32 | if not self.highlighting_on: | |
33 | for prompt in (self._frontend._continuation_prompt, |
|
33 | return | |
34 | self._frontend._prompt): |
|
34 | ||
35 | if qstring.startsWith(prompt): |
|
35 | # The input to this function is unicode string that may contain | |
36 | qstring.remove(0, len(prompt)) |
|
36 | # paragraph break characters, non-breaking spaces, etc. Here we acquire | |
37 | self._current_offset = len(prompt) |
|
37 | # the string as plain text so we can compare it. | |
38 | break |
|
38 | current_block = self.currentBlock() | |
39 | PygmentsHighlighter.highlightBlock(self, qstring) |
|
39 | string = self._frontend._get_block_plain_text(current_block) | |
|
40 | ||||
|
41 | # Decide whether to check for the regular or continuation prompt. | |||
|
42 | if current_block.contains(self._frontend._prompt_pos): | |||
|
43 | prompt = self._frontend._prompt | |||
|
44 | else: | |||
|
45 | prompt = self._frontend._continuation_prompt | |||
|
46 | ||||
|
47 | # Don't highlight the part of the string that contains the prompt. | |||
|
48 | if string.startswith(prompt): | |||
|
49 | self._current_offset = len(prompt) | |||
|
50 | qstring.remove(0, len(prompt)) | |||
|
51 | else: | |||
|
52 | self._current_offset = 0 | |||
|
53 | ||||
|
54 | PygmentsHighlighter.highlightBlock(self, qstring) | |||
40 |
|
55 | |||
41 | def setFormat(self, start, count, format): |
|
56 | def setFormat(self, start, count, format): | |
42 |
""" Reimplemented to |
|
57 | """ Reimplemented to highlight selectively. | |
43 | """ |
|
58 | """ | |
44 | start += self._current_offset |
|
59 | start += self._current_offset | |
45 | PygmentsHighlighter.setFormat(self, start, count, format) |
|
60 | PygmentsHighlighter.setFormat(self, start, count, format) | |
@@ -59,9 +74,6 b' class FrontendWidget(HistoryConsoleWidget):' | |||||
59 | def __init__(self, parent=None): |
|
74 | def __init__(self, parent=None): | |
60 | super(FrontendWidget, self).__init__(parent) |
|
75 | super(FrontendWidget, self).__init__(parent) | |
61 |
|
76 | |||
62 | # ConsoleWidget protected variables. |
|
|||
63 | self._continuation_prompt = '... ' |
|
|||
64 |
|
||||
65 | # FrontendWidget protected variables. |
|
77 | # FrontendWidget protected variables. | |
66 | self._call_tip_widget = CallTipWidget(self) |
|
78 | self._call_tip_widget = CallTipWidget(self) | |
67 | self._completion_lexer = CompletionLexer(PythonLexer()) |
|
79 | self._completion_lexer = CompletionLexer(PythonLexer()) | |
@@ -70,6 +82,9 b' class FrontendWidget(HistoryConsoleWidget):' | |||||
70 | self._input_splitter = InputSplitter(input_mode='replace') |
|
82 | self._input_splitter = InputSplitter(input_mode='replace') | |
71 | self._kernel_manager = None |
|
83 | self._kernel_manager = None | |
72 |
|
84 | |||
|
85 | # Configure the ConsoleWidget. | |||
|
86 | self._set_continuation_prompt('... ') | |||
|
87 | ||||
73 | self.document().contentsChange.connect(self._document_contents_change) |
|
88 | self.document().contentsChange.connect(self._document_contents_change) | |
74 |
|
89 | |||
75 | #--------------------------------------------------------------------------- |
|
90 | #--------------------------------------------------------------------------- | |
@@ -143,17 +158,6 b' class FrontendWidget(HistoryConsoleWidget):' | |||||
143 | return False |
|
158 | return False | |
144 |
|
159 | |||
145 | #--------------------------------------------------------------------------- |
|
160 | #--------------------------------------------------------------------------- | |
146 | # 'ConsoleWidget' protected interface |
|
|||
147 | #--------------------------------------------------------------------------- |
|
|||
148 |
|
||||
149 | def _show_prompt(self, prompt=None, newline=True): |
|
|||
150 | """ Reimplemented to set a default prompt. |
|
|||
151 | """ |
|
|||
152 | if prompt is None: |
|
|||
153 | prompt = '>>> ' |
|
|||
154 | super(FrontendWidget, self)._show_prompt(prompt, newline) |
|
|||
155 |
|
||||
156 | #--------------------------------------------------------------------------- |
|
|||
157 | # 'FrontendWidget' interface |
|
161 | # 'FrontendWidget' interface | |
158 | #--------------------------------------------------------------------------- |
|
162 | #--------------------------------------------------------------------------- | |
159 |
|
163 | |||
@@ -283,20 +287,24 b' class FrontendWidget(HistoryConsoleWidget):' | |||||
283 | self.appendPlainText('Kernel process is either remote or ' |
|
287 | self.appendPlainText('Kernel process is either remote or ' | |
284 | 'unspecified. Cannot interrupt.\n') |
|
288 | 'unspecified. Cannot interrupt.\n') | |
285 |
|
289 | |||
|
290 | def _show_interpreter_prompt(self): | |||
|
291 | """ Shows a prompt for the interpreter. | |||
|
292 | """ | |||
|
293 | self._show_prompt('>>> ') | |||
|
294 | ||||
286 | #------ Signal handlers ---------------------------------------------------- |
|
295 | #------ Signal handlers ---------------------------------------------------- | |
287 |
|
296 | |||
288 | def _started_channels(self): |
|
297 | def _started_channels(self): | |
289 | """ Called when the kernel manager has started listening. |
|
298 | """ Called when the kernel manager has started listening. | |
290 | """ |
|
299 | """ | |
291 | QtGui.QPlainTextEdit.clear(self) |
|
300 | self._reset() | |
292 | if self._reading: |
|
|||
293 | self._reading = False |
|
|||
294 | self.appendPlainText(self._get_banner()) |
|
301 | self.appendPlainText(self._get_banner()) | |
295 | self._show_prompt() |
|
302 | self._show_interpreter_prompt() | |
296 |
|
303 | |||
297 | def _stopped_channels(self): |
|
304 | def _stopped_channels(self): | |
298 | """ Called when the kernel manager has stopped listening. |
|
305 | """ Called when the kernel manager has stopped listening. | |
299 | """ |
|
306 | """ | |
|
307 | # FIXME: Print a message here? | |||
300 | pass |
|
308 | pass | |
301 |
|
309 | |||
302 | def _document_contents_change(self, position, removed, added): |
|
310 | def _document_contents_change(self, position, removed, added): | |
@@ -327,9 +335,7 b' class FrontendWidget(HistoryConsoleWidget):' | |||||
327 | handler(omsg) |
|
335 | handler(omsg) | |
328 |
|
336 | |||
329 | def _handle_pyout(self, omsg): |
|
337 | def _handle_pyout(self, omsg): | |
330 | session = omsg['parent_header']['session'] |
|
338 | self.appendPlainText(omsg['content']['data'] + '\n') | |
331 | if session == self.kernel_manager.session.session: |
|
|||
332 | self.appendPlainText(omsg['content']['data'] + '\n') |
|
|||
333 |
|
339 | |||
334 | def _handle_stream(self, omsg): |
|
340 | def _handle_stream(self, omsg): | |
335 | self.appendPlainText(omsg['content']['data']) |
|
341 | self.appendPlainText(omsg['content']['data']) | |
@@ -351,7 +357,7 b' class FrontendWidget(HistoryConsoleWidget):' | |||||
351 | text = "ERROR: ABORTED\n" |
|
357 | text = "ERROR: ABORTED\n" | |
352 | self.appendPlainText(text) |
|
358 | self.appendPlainText(text) | |
353 | self._hidden = True |
|
359 | self._hidden = True | |
354 | self._show_prompt() |
|
360 | self._show_interpreter_prompt() | |
355 | self.executed.emit(rep) |
|
361 | self.executed.emit(rep) | |
356 |
|
362 | |||
357 | def _handle_complete_reply(self, rep): |
|
363 | def _handle_complete_reply(self, rep): |
@@ -10,6 +10,14 b' class IPythonWidget(FrontendWidget):' | |||||
10 | """ A FrontendWidget for an IPython kernel. |
|
10 | """ A FrontendWidget for an IPython kernel. | |
11 | """ |
|
11 | """ | |
12 |
|
12 | |||
|
13 | # The default stylesheet for prompts, colors, etc. | |||
|
14 | default_stylesheet = """ | |||
|
15 | .in-prompt { color: navy; } | |||
|
16 | .in-prompt-number { font-weight: bold; } | |||
|
17 | .out-prompt { color: darkred; } | |||
|
18 | .out-prompt-number { font-weight: bold; } | |||
|
19 | """ | |||
|
20 | ||||
13 | #--------------------------------------------------------------------------- |
|
21 | #--------------------------------------------------------------------------- | |
14 | # 'QObject' interface |
|
22 | # 'QObject' interface | |
15 | #--------------------------------------------------------------------------- |
|
23 | #--------------------------------------------------------------------------- | |
@@ -17,7 +25,12 b' class IPythonWidget(FrontendWidget):' | |||||
17 | def __init__(self, parent=None): |
|
25 | def __init__(self, parent=None): | |
18 | super(IPythonWidget, self).__init__(parent) |
|
26 | super(IPythonWidget, self).__init__(parent) | |
19 |
|
27 | |||
|
28 | # Initialize protected variables. | |||
20 | self._magic_overrides = {} |
|
29 | self._magic_overrides = {} | |
|
30 | self._prompt_count = 0 | |||
|
31 | ||||
|
32 | # Set a default stylesheet. | |||
|
33 | self.set_style_sheet(self.default_stylesheet) | |||
21 |
|
34 | |||
22 | #--------------------------------------------------------------------------- |
|
35 | #--------------------------------------------------------------------------- | |
23 | # 'ConsoleWidget' abstract interface |
|
36 | # 'ConsoleWidget' abstract interface | |
@@ -38,7 +51,7 b' class IPythonWidget(FrontendWidget):' | |||||
38 | output = callback(arguments) |
|
51 | output = callback(arguments) | |
39 | if output: |
|
52 | if output: | |
40 | self.appendPlainText(output) |
|
53 | self.appendPlainText(output) | |
41 | self._show_prompt() |
|
54 | self._show_interpreter_prompt() | |
42 | else: |
|
55 | else: | |
43 | super(IPythonWidget, self)._execute(source, hidden) |
|
56 | super(IPythonWidget, self)._execute(source, hidden) | |
44 |
|
57 | |||
@@ -56,10 +69,36 b' class IPythonWidget(FrontendWidget):' | |||||
56 | #--------------------------------------------------------------------------- |
|
69 | #--------------------------------------------------------------------------- | |
57 |
|
70 | |||
58 | def _get_banner(self): |
|
71 | def _get_banner(self): | |
59 |
""" Reimplemented to |
|
72 | """ Reimplemented to return IPython's default banner. | |
60 | """ |
|
73 | """ | |
61 | return default_banner |
|
74 | return default_banner | |
62 |
|
75 | |||
|
76 | def _show_interpreter_prompt(self): | |||
|
77 | """ Reimplemented for IPython-style prompts. | |||
|
78 | """ | |||
|
79 | self._prompt_count += 1 | |||
|
80 | prompt_template = '<span class="in-prompt">%s</span>' | |||
|
81 | prompt_body = '<br/>In [<span class="in-prompt-number">%i</span>]: ' | |||
|
82 | prompt = (prompt_template % prompt_body) % self._prompt_count | |||
|
83 | self._show_prompt(prompt, html=True) | |||
|
84 | ||||
|
85 | # Update continuation prompt to reflect (possibly) new prompt length. | |||
|
86 | cont_prompt_chars = '...: ' | |||
|
87 | space_count = len(self._prompt.lstrip()) - len(cont_prompt_chars) | |||
|
88 | cont_prompt_body = ' ' * space_count + cont_prompt_chars | |||
|
89 | self._continuation_prompt_html = prompt_template % cont_prompt_body | |||
|
90 | ||||
|
91 | #------ Signal handlers ---------------------------------------------------- | |||
|
92 | ||||
|
93 | def _handle_pyout(self, omsg): | |||
|
94 | """ Reimplemented for IPython-style "display hook". | |||
|
95 | """ | |||
|
96 | prompt_template = '<span class="out-prompt">%s</span>' | |||
|
97 | prompt_body = 'Out[<span class="out-prompt-number">%i</span>]: ' | |||
|
98 | prompt = (prompt_template % prompt_body) % self._prompt_count | |||
|
99 | self.appendHtml(prompt) | |||
|
100 | self.appendPlainText(omsg['content']['data'] + '\n') | |||
|
101 | ||||
63 | #--------------------------------------------------------------------------- |
|
102 | #--------------------------------------------------------------------------- | |
64 | # 'IPythonWidget' interface |
|
103 | # 'IPythonWidget' interface | |
65 | #--------------------------------------------------------------------------- |
|
104 | #--------------------------------------------------------------------------- | |
@@ -81,6 +120,11 b' class IPythonWidget(FrontendWidget):' | |||||
81 | except KeyError: |
|
120 | except KeyError: | |
82 | pass |
|
121 | pass | |
83 |
|
122 | |||
|
123 | def set_style_sheet(self, stylesheet): | |||
|
124 | """ Sets the style sheet. | |||
|
125 | """ | |||
|
126 | self.document().setDefaultStyleSheet(stylesheet) | |||
|
127 | ||||
84 |
|
128 | |||
85 | if __name__ == '__main__': |
|
129 | if __name__ == '__main__': | |
86 | from IPython.frontend.qt.kernelmanager import QtKernelManager |
|
130 | from IPython.frontend.qt.kernelmanager import QtKernelManager |
@@ -1,7 +1,7 b'' | |||||
1 | # System library imports. |
|
1 | # System library imports. | |
2 | from PyQt4 import QtGui |
|
2 | from PyQt4 import QtGui | |
3 | from pygments.lexer import RegexLexer, _TokenType, Text, Error |
|
3 | from pygments.lexer import RegexLexer, _TokenType, Text, Error | |
4 |
from pygments.lexers import |
|
4 | from pygments.lexers import PythonLexer | |
5 | from pygments.styles.default import DefaultStyle |
|
5 | from pygments.styles.default import DefaultStyle | |
6 | from pygments.token import Comment |
|
6 | from pygments.token import Comment | |
7 |
|
7 | |||
@@ -133,7 +133,7 b' class PygmentsHighlighter(QtGui.QSyntaxHighlighter):' | |||||
133 | if token in self._formats: |
|
133 | if token in self._formats: | |
134 | return self._formats[token] |
|
134 | return self._formats[token] | |
135 | result = None |
|
135 | result = None | |
136 |
for key, value in self._style.style_for_token(token) |
|
136 | for key, value in self._style.style_for_token(token).items(): | |
137 | if value: |
|
137 | if value: | |
138 | if result is None: |
|
138 | if result is None: | |
139 | result = QtGui.QTextCharFormat() |
|
139 | result = QtGui.QTextCharFormat() | |
@@ -171,12 +171,11 b' class PygmentsHighlighter(QtGui.QSyntaxHighlighter):' | |||||
171 | qcolor = self._get_color(color) |
|
171 | qcolor = self._get_color(color) | |
172 | result = QtGui.QBrush(qcolor) |
|
172 | result = QtGui.QBrush(qcolor) | |
173 | self._brushes[color] = result |
|
173 | self._brushes[color] = result | |
174 |
|
||||
175 | return result |
|
174 | return result | |
176 |
|
175 | |||
177 | def _get_color(self, color): |
|
176 | def _get_color(self, color): | |
178 | qcolor = QtGui.QColor() |
|
177 | qcolor = QtGui.QColor() | |
179 | qcolor.setRgb(int(color[:2],base=16), |
|
178 | qcolor.setRgb(int(color[:2], base=16), | |
180 | int(color[2:4], base=16), |
|
179 | int(color[2:4], base=16), | |
181 | int(color[4:6], base=16)) |
|
180 | int(color[4:6], base=16)) | |
182 | return qcolor |
|
181 | return qcolor |
General Comments 0
You need to be logged in to leave comments.
Login now