##// END OF EJS Templates
Added a method on IPythonWidget for setting the style to the IPython defaults.
epatters -
Show More
@@ -1,359 +1,393 b''
1 """ A FrontendWidget that emulates the interface of the console IPython and
1 """ A FrontendWidget that emulates the interface of the console IPython and
2 supports the additional functionality provided by the IPython kernel.
2 supports the additional functionality provided by the IPython kernel.
3
3
4 TODO: Add support for retrieving the system default editor. Requires code
4 TODO: Add support for retrieving the system default editor. Requires code
5 paths for Windows (use the registry), Mac OS (use LaunchServices), and
5 paths for Windows (use the registry), Mac OS (use LaunchServices), and
6 Linux (use the xdg system).
6 Linux (use the xdg system).
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
10 # Imports
11 #-----------------------------------------------------------------------------
12
9 # Standard library imports
13 # Standard library imports
10 from collections import namedtuple
14 from collections import namedtuple
11 from subprocess import Popen
15 from subprocess import Popen
12
16
13 # System library imports
17 # System library imports
14 from PyQt4 import QtCore, QtGui
18 from PyQt4 import QtCore, QtGui
15
19
16 # Local imports
20 # Local imports
17 from IPython.core.inputsplitter import IPythonInputSplitter
21 from IPython.core.inputsplitter import IPythonInputSplitter
18 from IPython.core.usage import default_banner
22 from IPython.core.usage import default_banner
19 from IPython.utils.traitlets import Bool, Str
23 from IPython.utils.traitlets import Bool, Str
20 from frontend_widget import FrontendWidget
24 from frontend_widget import FrontendWidget
21
25
22 # The default style sheet: black text on a white background.
26 #-----------------------------------------------------------------------------
23 default_style_sheet = '''
27 # Constants
28 #-----------------------------------------------------------------------------
29
30 # The default light style sheet: black text on a white background.
31 default_light_style_sheet = '''
24 .error { color: red; }
32 .error { color: red; }
25 .in-prompt { color: navy; }
33 .in-prompt { color: navy; }
26 .in-prompt-number { font-weight: bold; }
34 .in-prompt-number { font-weight: bold; }
27 .out-prompt { color: darkred; }
35 .out-prompt { color: darkred; }
28 .out-prompt-number { font-weight: bold; }
36 .out-prompt-number { font-weight: bold; }
29 '''
37 '''
30 default_syntax_style = 'default'
38 default_light_syntax_style = 'default'
31
39
32 # A dark style sheet: white text on a black background.
40 # The default dark style sheet: white text on a black background.
33 dark_style_sheet = '''
41 default_dark_style_sheet = '''
34 QPlainTextEdit, QTextEdit { background-color: black; color: white }
42 QPlainTextEdit, QTextEdit { background-color: black; color: white }
35 QFrame { border: 1px solid grey; }
43 QFrame { border: 1px solid grey; }
36 .error { color: red; }
44 .error { color: red; }
37 .in-prompt { color: lime; }
45 .in-prompt { color: lime; }
38 .in-prompt-number { color: lime; font-weight: bold; }
46 .in-prompt-number { color: lime; font-weight: bold; }
39 .out-prompt { color: red; }
47 .out-prompt { color: red; }
40 .out-prompt-number { color: red; font-weight: bold; }
48 .out-prompt-number { color: red; font-weight: bold; }
41 '''
49 '''
42 dark_syntax_style = 'monokai'
50 default_dark_syntax_style = 'monokai'
43
51
44 # Default prompts.
52 # Default prompts.
45 default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
53 default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
46 default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
54 default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
47
55
56 #-----------------------------------------------------------------------------
57 # IPythonWidget class
58 #-----------------------------------------------------------------------------
48
59
49 class IPythonWidget(FrontendWidget):
60 class IPythonWidget(FrontendWidget):
50 """ A FrontendWidget for an IPython kernel.
61 """ A FrontendWidget for an IPython kernel.
51 """
62 """
52
63
53 # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
64 # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
54 # an editor is needed for a file. This overrides 'editor' and 'editor_line'
65 # an editor is needed for a file. This overrides 'editor' and 'editor_line'
55 # settings.
66 # settings.
56 custom_edit = Bool(False)
67 custom_edit = Bool(False)
57 custom_edit_requested = QtCore.pyqtSignal(object, object)
68 custom_edit_requested = QtCore.pyqtSignal(object, object)
58
69
59 # A command for invoking a system text editor. If the string contains a
70 # A command for invoking a system text editor. If the string contains a
60 # {filename} format specifier, it will be used. Otherwise, the filename will
71 # {filename} format specifier, it will be used. Otherwise, the filename will
61 # be appended to the end the command.
72 # be appended to the end the command.
62 editor = Str('default', config=True)
73 editor = Str('default', config=True)
63
74
64 # The editor command to use when a specific line number is requested. The
75 # The editor command to use when a specific line number is requested. The
65 # string should contain two format specifiers: {line} and {filename}. If
76 # string should contain two format specifiers: {line} and {filename}. If
66 # this parameter is not specified, the line number option to the %edit magic
77 # this parameter is not specified, the line number option to the %edit magic
67 # will be ignored.
78 # will be ignored.
68 editor_line = Str(config=True)
79 editor_line = Str(config=True)
69
80
70 # A CSS stylesheet. The stylesheet can contain classes for:
81 # A CSS stylesheet. The stylesheet can contain classes for:
71 # 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
82 # 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
72 # 2. Pygments: .c, .k, .o, etc (see PygmentsHighlighter)
83 # 2. Pygments: .c, .k, .o, etc (see PygmentsHighlighter)
73 # 3. IPython: .error, .in-prompt, .out-prompt, etc
84 # 3. IPython: .error, .in-prompt, .out-prompt, etc
74 style_sheet = Str(default_style_sheet, config=True)
85 style_sheet = Str(config=True)
75
86
76 # If not empty, use this Pygments style for syntax highlighting. Otherwise,
87 # If not empty, use this Pygments style for syntax highlighting. Otherwise,
77 # the style sheet is queried for Pygments style information.
88 # the style sheet is queried for Pygments style information.
78 syntax_style = Str(default_syntax_style, config=True)
89 syntax_style = Str(config=True)
79
90
80 # Prompts.
91 # Prompts.
81 in_prompt = Str(default_in_prompt, config=True)
92 in_prompt = Str(default_in_prompt, config=True)
82 out_prompt = Str(default_out_prompt, config=True)
93 out_prompt = Str(default_out_prompt, config=True)
83
94
84 # FrontendWidget protected class variables.
95 # FrontendWidget protected class variables.
85 _input_splitter_class = IPythonInputSplitter
96 _input_splitter_class = IPythonInputSplitter
86
97
87 # IPythonWidget protected class variables.
98 # IPythonWidget protected class variables.
88 _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
99 _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
89 _payload_source_edit = 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic'
100 _payload_source_edit = 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic'
90 _payload_source_page = 'IPython.zmq.page.page'
101 _payload_source_page = 'IPython.zmq.page.page'
91
102
92 #---------------------------------------------------------------------------
103 #---------------------------------------------------------------------------
93 # 'object' interface
104 # 'object' interface
94 #---------------------------------------------------------------------------
105 #---------------------------------------------------------------------------
95
106
96 def __init__(self, *args, **kw):
107 def __init__(self, *args, **kw):
97 super(IPythonWidget, self).__init__(*args, **kw)
108 super(IPythonWidget, self).__init__(*args, **kw)
98
109
99 # IPythonWidget protected variables.
110 # IPythonWidget protected variables.
100 self._previous_prompt_obj = None
111 self._previous_prompt_obj = None
101
112
102 # Initialize widget styling.
113 # Initialize widget styling.
103 self._style_sheet_changed()
114 if self.style_sheet:
104 self._syntax_style_changed()
115 self._style_sheet_changed()
116 self._syntax_style_changed()
117 else:
118 self.set_default_style()
105
119
106 #---------------------------------------------------------------------------
120 #---------------------------------------------------------------------------
107 # 'BaseFrontendMixin' abstract interface
121 # 'BaseFrontendMixin' abstract interface
108 #---------------------------------------------------------------------------
122 #---------------------------------------------------------------------------
109
123
110 def _handle_complete_reply(self, rep):
124 def _handle_complete_reply(self, rep):
111 """ Reimplemented to support IPython's improved completion machinery.
125 """ Reimplemented to support IPython's improved completion machinery.
112 """
126 """
113 cursor = self._get_cursor()
127 cursor = self._get_cursor()
114 if rep['parent_header']['msg_id'] == self._complete_id and \
128 if rep['parent_header']['msg_id'] == self._complete_id and \
115 cursor.position() == self._complete_pos:
129 cursor.position() == self._complete_pos:
116 # The completer tells us what text was actually used for the
130 # The completer tells us what text was actually used for the
117 # matching, so we must move that many characters left to apply the
131 # matching, so we must move that many characters left to apply the
118 # completions.
132 # completions.
119 text = rep['content']['matched_text']
133 text = rep['content']['matched_text']
120 cursor.movePosition(QtGui.QTextCursor.Left, n=len(text))
134 cursor.movePosition(QtGui.QTextCursor.Left, n=len(text))
121 self._complete_with_items(cursor, rep['content']['matches'])
135 self._complete_with_items(cursor, rep['content']['matches'])
122
136
123 def _handle_history_reply(self, msg):
137 def _handle_history_reply(self, msg):
124 """ Implemented to handle history replies, which are only supported by
138 """ Implemented to handle history replies, which are only supported by
125 the IPython kernel.
139 the IPython kernel.
126 """
140 """
127 history_dict = msg['content']['history']
141 history_dict = msg['content']['history']
128 items = [ history_dict[key] for key in sorted(history_dict.keys()) ]
142 items = [ history_dict[key] for key in sorted(history_dict.keys()) ]
129 self._set_history(items)
143 self._set_history(items)
130
144
131 def _handle_prompt_reply(self, msg):
145 def _handle_prompt_reply(self, msg):
132 """ Implemented to handle prompt number replies, which are only
146 """ Implemented to handle prompt number replies, which are only
133 supported by the IPython kernel.
147 supported by the IPython kernel.
134 """
148 """
135 content = msg['content']
149 content = msg['content']
136 self._show_interpreter_prompt(content['prompt_number'],
150 self._show_interpreter_prompt(content['prompt_number'],
137 content['input_sep'])
151 content['input_sep'])
138
152
139 def _handle_pyout(self, msg):
153 def _handle_pyout(self, msg):
140 """ Reimplemented for IPython-style "display hook".
154 """ Reimplemented for IPython-style "display hook".
141 """
155 """
142 if not self._hidden and self._is_from_this_session(msg):
156 if not self._hidden and self._is_from_this_session(msg):
143 content = msg['content']
157 content = msg['content']
144 prompt_number = content['prompt_number']
158 prompt_number = content['prompt_number']
145 self._append_plain_text(content['output_sep'])
159 self._append_plain_text(content['output_sep'])
146 self._append_html(self._make_out_prompt(prompt_number))
160 self._append_html(self._make_out_prompt(prompt_number))
147 self._append_plain_text(content['data'] + '\n' +
161 self._append_plain_text(content['data'] + '\n' +
148 content['output_sep2'])
162 content['output_sep2'])
149
163
150 def _started_channels(self):
164 def _started_channels(self):
151 """ Reimplemented to make a history request.
165 """ Reimplemented to make a history request.
152 """
166 """
153 super(IPythonWidget, self)._started_channels()
167 super(IPythonWidget, self)._started_channels()
154 # FIXME: Disabled until history requests are properly implemented.
168 # FIXME: Disabled until history requests are properly implemented.
155 #self.kernel_manager.xreq_channel.history(raw=True, output=False)
169 #self.kernel_manager.xreq_channel.history(raw=True, output=False)
156
170
157 #---------------------------------------------------------------------------
171 #---------------------------------------------------------------------------
158 # 'FrontendWidget' interface
172 # 'FrontendWidget' interface
159 #---------------------------------------------------------------------------
173 #---------------------------------------------------------------------------
160
174
161 def execute_file(self, path, hidden=False):
175 def execute_file(self, path, hidden=False):
162 """ Reimplemented to use the 'run' magic.
176 """ Reimplemented to use the 'run' magic.
163 """
177 """
164 self.execute('%%run %s' % path, hidden=hidden)
178 self.execute('%%run %s' % path, hidden=hidden)
165
179
166 #---------------------------------------------------------------------------
180 #---------------------------------------------------------------------------
167 # 'FrontendWidget' protected interface
181 # 'FrontendWidget' protected interface
168 #---------------------------------------------------------------------------
182 #---------------------------------------------------------------------------
169
183
170 def _complete(self):
184 def _complete(self):
171 """ Reimplemented to support IPython's improved completion machinery.
185 """ Reimplemented to support IPython's improved completion machinery.
172 """
186 """
173 # We let the kernel split the input line, so we *always* send an empty
187 # We let the kernel split the input line, so we *always* send an empty
174 # text field. Readline-based frontends do get a real text field which
188 # text field. Readline-based frontends do get a real text field which
175 # they can use.
189 # they can use.
176 text = ''
190 text = ''
177
191
178 # Send the completion request to the kernel
192 # Send the completion request to the kernel
179 self._complete_id = self.kernel_manager.xreq_channel.complete(
193 self._complete_id = self.kernel_manager.xreq_channel.complete(
180 text, # text
194 text, # text
181 self._get_input_buffer_cursor_line(), # line
195 self._get_input_buffer_cursor_line(), # line
182 self._get_input_buffer_cursor_column(), # cursor_pos
196 self._get_input_buffer_cursor_column(), # cursor_pos
183 self.input_buffer) # block
197 self.input_buffer) # block
184 self._complete_pos = self._get_cursor().position()
198 self._complete_pos = self._get_cursor().position()
185
199
186 def _get_banner(self):
200 def _get_banner(self):
187 """ Reimplemented to return IPython's default banner.
201 """ Reimplemented to return IPython's default banner.
188 """
202 """
189 return default_banner + '\n'
203 return default_banner + '\n'
190
204
191 def _process_execute_error(self, msg):
205 def _process_execute_error(self, msg):
192 """ Reimplemented for IPython-style traceback formatting.
206 """ Reimplemented for IPython-style traceback formatting.
193 """
207 """
194 content = msg['content']
208 content = msg['content']
195 traceback = '\n'.join(content['traceback']) + '\n'
209 traceback = '\n'.join(content['traceback']) + '\n'
196 if False:
210 if False:
197 # FIXME: For now, tracebacks come as plain text, so we can't use
211 # FIXME: For now, tracebacks come as plain text, so we can't use
198 # the html renderer yet. Once we refactor ultratb to produce
212 # the html renderer yet. Once we refactor ultratb to produce
199 # properly styled tracebacks, this branch should be the default
213 # properly styled tracebacks, this branch should be the default
200 traceback = traceback.replace(' ', '&nbsp;')
214 traceback = traceback.replace(' ', '&nbsp;')
201 traceback = traceback.replace('\n', '<br/>')
215 traceback = traceback.replace('\n', '<br/>')
202
216
203 ename = content['ename']
217 ename = content['ename']
204 ename_styled = '<span class="error">%s</span>' % ename
218 ename_styled = '<span class="error">%s</span>' % ename
205 traceback = traceback.replace(ename, ename_styled)
219 traceback = traceback.replace(ename, ename_styled)
206
220
207 self._append_html(traceback)
221 self._append_html(traceback)
208 else:
222 else:
209 # This is the fallback for now, using plain text with ansi escapes
223 # This is the fallback for now, using plain text with ansi escapes
210 self._append_plain_text(traceback)
224 self._append_plain_text(traceback)
211
225
212 def _process_execute_payload(self, item):
226 def _process_execute_payload(self, item):
213 """ Reimplemented to handle %edit and paging payloads.
227 """ Reimplemented to handle %edit and paging payloads.
214 """
228 """
215 if item['source'] == self._payload_source_edit:
229 if item['source'] == self._payload_source_edit:
216 self._edit(item['filename'], item['line_number'])
230 self._edit(item['filename'], item['line_number'])
217 return True
231 return True
218 elif item['source'] == self._payload_source_page:
232 elif item['source'] == self._payload_source_page:
219 self._page(item['data'])
233 self._page(item['data'])
220 return True
234 return True
221 else:
235 else:
222 return False
236 return False
223
237
224 def _show_interpreter_prompt(self, number=None, input_sep='\n'):
238 def _show_interpreter_prompt(self, number=None, input_sep='\n'):
225 """ Reimplemented for IPython-style prompts.
239 """ Reimplemented for IPython-style prompts.
226 """
240 """
227 # If a number was not specified, make a prompt number request.
241 # If a number was not specified, make a prompt number request.
228 if number is None:
242 if number is None:
229 self.kernel_manager.xreq_channel.prompt()
243 self.kernel_manager.xreq_channel.prompt()
230 return
244 return
231
245
232 # Show a new prompt and save information about it so that it can be
246 # Show a new prompt and save information about it so that it can be
233 # updated later if the prompt number turns out to be wrong.
247 # updated later if the prompt number turns out to be wrong.
234 self._prompt_sep = input_sep
248 self._prompt_sep = input_sep
235 self._show_prompt(self._make_in_prompt(number), html=True)
249 self._show_prompt(self._make_in_prompt(number), html=True)
236 block = self._control.document().lastBlock()
250 block = self._control.document().lastBlock()
237 length = len(self._prompt)
251 length = len(self._prompt)
238 self._previous_prompt_obj = self._PromptBlock(block, length, number)
252 self._previous_prompt_obj = self._PromptBlock(block, length, number)
239
253
240 # Update continuation prompt to reflect (possibly) new prompt length.
254 # Update continuation prompt to reflect (possibly) new prompt length.
241 self._set_continuation_prompt(
255 self._set_continuation_prompt(
242 self._make_continuation_prompt(self._prompt), html=True)
256 self._make_continuation_prompt(self._prompt), html=True)
243
257
244 def _show_interpreter_prompt_for_reply(self, msg):
258 def _show_interpreter_prompt_for_reply(self, msg):
245 """ Reimplemented for IPython-style prompts.
259 """ Reimplemented for IPython-style prompts.
246 """
260 """
247 # Update the old prompt number if necessary.
261 # Update the old prompt number if necessary.
248 content = msg['content']
262 content = msg['content']
249 previous_prompt_number = content['prompt_number']
263 previous_prompt_number = content['prompt_number']
250 if self._previous_prompt_obj and \
264 if self._previous_prompt_obj and \
251 self._previous_prompt_obj.number != previous_prompt_number:
265 self._previous_prompt_obj.number != previous_prompt_number:
252 block = self._previous_prompt_obj.block
266 block = self._previous_prompt_obj.block
253
267
254 # Make sure the prompt block has not been erased.
268 # Make sure the prompt block has not been erased.
255 if block.isValid() and not block.text().isEmpty():
269 if block.isValid() and not block.text().isEmpty():
256
270
257 # Remove the old prompt and insert a new prompt.
271 # Remove the old prompt and insert a new prompt.
258 cursor = QtGui.QTextCursor(block)
272 cursor = QtGui.QTextCursor(block)
259 cursor.movePosition(QtGui.QTextCursor.Right,
273 cursor.movePosition(QtGui.QTextCursor.Right,
260 QtGui.QTextCursor.KeepAnchor,
274 QtGui.QTextCursor.KeepAnchor,
261 self._previous_prompt_obj.length)
275 self._previous_prompt_obj.length)
262 prompt = self._make_in_prompt(previous_prompt_number)
276 prompt = self._make_in_prompt(previous_prompt_number)
263 self._prompt = self._insert_html_fetching_plain_text(
277 self._prompt = self._insert_html_fetching_plain_text(
264 cursor, prompt)
278 cursor, prompt)
265
279
266 # When the HTML is inserted, Qt blows away the syntax
280 # When the HTML is inserted, Qt blows away the syntax
267 # highlighting for the line, so we need to rehighlight it.
281 # highlighting for the line, so we need to rehighlight it.
268 self._highlighter.rehighlightBlock(cursor.block())
282 self._highlighter.rehighlightBlock(cursor.block())
269
283
270 self._previous_prompt_obj = None
284 self._previous_prompt_obj = None
271
285
272 # Show a new prompt with the kernel's estimated prompt number.
286 # Show a new prompt with the kernel's estimated prompt number.
273 next_prompt = content['next_prompt']
287 next_prompt = content['next_prompt']
274 self._show_interpreter_prompt(next_prompt['prompt_number'],
288 self._show_interpreter_prompt(next_prompt['prompt_number'],
275 next_prompt['input_sep'])
289 next_prompt['input_sep'])
276
290
277 #---------------------------------------------------------------------------
291 #---------------------------------------------------------------------------
292 # 'IPythonWidget' interface
293 #---------------------------------------------------------------------------
294
295 def set_default_style(self, lightbg=True):
296 """ Sets the widget style to the class defaults.
297
298 Parameters:
299 -----------
300 lightbg : bool, optional (default True)
301 Whether to use the default IPython light background or dark
302 background style.
303 """
304 if lightbg:
305 self.style_sheet = default_light_style_sheet
306 self.syntax_style = default_light_syntax_style
307 else:
308 self.style_sheet = default_dark_style_sheet
309 self.syntax_style = default_dark_syntax_style
310
311 #---------------------------------------------------------------------------
278 # 'IPythonWidget' protected interface
312 # 'IPythonWidget' protected interface
279 #---------------------------------------------------------------------------
313 #---------------------------------------------------------------------------
280
314
281 def _edit(self, filename, line=None):
315 def _edit(self, filename, line=None):
282 """ Opens a Python script for editing.
316 """ Opens a Python script for editing.
283
317
284 Parameters:
318 Parameters:
285 -----------
319 -----------
286 filename : str
320 filename : str
287 A path to a local system file.
321 A path to a local system file.
288
322
289 line : int, optional
323 line : int, optional
290 A line of interest in the file.
324 A line of interest in the file.
291 """
325 """
292 if self.custom_edit:
326 if self.custom_edit:
293 self.custom_edit_requested.emit(filename, line)
327 self.custom_edit_requested.emit(filename, line)
294 elif self.editor == 'default':
328 elif self.editor == 'default':
295 self._append_plain_text('No default editor available.\n')
329 self._append_plain_text('No default editor available.\n')
296 else:
330 else:
297 try:
331 try:
298 filename = '"%s"' % filename
332 filename = '"%s"' % filename
299 if line and self.editor_line:
333 if line and self.editor_line:
300 command = self.editor_line.format(filename=filename,
334 command = self.editor_line.format(filename=filename,
301 line=line)
335 line=line)
302 else:
336 else:
303 try:
337 try:
304 command = self.editor.format()
338 command = self.editor.format()
305 except KeyError:
339 except KeyError:
306 command = self.editor.format(filename=filename)
340 command = self.editor.format(filename=filename)
307 else:
341 else:
308 command += ' ' + filename
342 command += ' ' + filename
309 except KeyError:
343 except KeyError:
310 self._append_plain_text('Invalid editor command.\n')
344 self._append_plain_text('Invalid editor command.\n')
311 else:
345 else:
312 try:
346 try:
313 Popen(command, shell=True)
347 Popen(command, shell=True)
314 except OSError:
348 except OSError:
315 msg = 'Opening editor with command "%s" failed.\n'
349 msg = 'Opening editor with command "%s" failed.\n'
316 self._append_plain_text(msg % command)
350 self._append_plain_text(msg % command)
317
351
318 def _make_in_prompt(self, number):
352 def _make_in_prompt(self, number):
319 """ Given a prompt number, returns an HTML In prompt.
353 """ Given a prompt number, returns an HTML In prompt.
320 """
354 """
321 body = self.in_prompt % number
355 body = self.in_prompt % number
322 return '<span class="in-prompt">%s</span>' % body
356 return '<span class="in-prompt">%s</span>' % body
323
357
324 def _make_continuation_prompt(self, prompt):
358 def _make_continuation_prompt(self, prompt):
325 """ Given a plain text version of an In prompt, returns an HTML
359 """ Given a plain text version of an In prompt, returns an HTML
326 continuation prompt.
360 continuation prompt.
327 """
361 """
328 end_chars = '...: '
362 end_chars = '...: '
329 space_count = len(prompt.lstrip('\n')) - len(end_chars)
363 space_count = len(prompt.lstrip('\n')) - len(end_chars)
330 body = '&nbsp;' * space_count + end_chars
364 body = '&nbsp;' * space_count + end_chars
331 return '<span class="in-prompt">%s</span>' % body
365 return '<span class="in-prompt">%s</span>' % body
332
366
333 def _make_out_prompt(self, number):
367 def _make_out_prompt(self, number):
334 """ Given a prompt number, returns an HTML Out prompt.
368 """ Given a prompt number, returns an HTML Out prompt.
335 """
369 """
336 body = self.out_prompt % number
370 body = self.out_prompt % number
337 return '<span class="out-prompt">%s</span>' % body
371 return '<span class="out-prompt">%s</span>' % body
338
372
339 #------ Trait change handlers ---------------------------------------------
373 #------ Trait change handlers ---------------------------------------------
340
374
341 def _style_sheet_changed(self):
375 def _style_sheet_changed(self):
342 """ Set the style sheets of the underlying widgets.
376 """ Set the style sheets of the underlying widgets.
343 """
377 """
344 self.setStyleSheet(self.style_sheet)
378 self.setStyleSheet(self.style_sheet)
345 self._control.document().setDefaultStyleSheet(self.style_sheet)
379 self._control.document().setDefaultStyleSheet(self.style_sheet)
346 if self._page_control:
380 if self._page_control:
347 self._page_control.document().setDefaultStyleSheet(self.style_sheet)
381 self._page_control.document().setDefaultStyleSheet(self.style_sheet)
348
382
349 bg_color = self._control.palette().background().color()
383 bg_color = self._control.palette().background().color()
350 self._ansi_processor.set_background_color(bg_color)
384 self._ansi_processor.set_background_color(bg_color)
351
385
352 def _syntax_style_changed(self):
386 def _syntax_style_changed(self):
353 """ Set the style for the syntax highlighter.
387 """ Set the style for the syntax highlighter.
354 """
388 """
355 if self.syntax_style:
389 if self.syntax_style:
356 self._highlighter.set_style(self.syntax_style)
390 self._highlighter.set_style(self.syntax_style)
357 else:
391 else:
358 self._highlighter.set_style_sheet(self.style_sheet)
392 self._highlighter.set_style_sheet(self.style_sheet)
359
393
General Comments 0
You need to be logged in to leave comments. Login now