##// END OF EJS Templates
adjust qtconsole color logic...
MinRK -
Show More
@@ -1,353 +1,356
1 1 """ A minimal application using the Qt console-style IPython frontend.
2 2
3 3 This is not a complete console app, as subprocess will not be able to receive
4 4 input, there is no real readline support, among other limitations.
5 5
6 6 Authors:
7 7
8 8 * Evan Patterson
9 9 * Min RK
10 10 * Erik Tollerud
11 11 * Fernando Perez
12 12 * Bussonnier Matthias
13 13 * Thomas Kluyver
14 14 * Paul Ivanov
15 15
16 16 """
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 # stdlib imports
23 23 import json
24 24 import os
25 25 import signal
26 26 import sys
27 27 import uuid
28 28
29 29 # System library imports
30 30 from IPython.external.qt import QtCore, QtGui
31 31
32 32 # Local imports
33 33 from IPython.config.application import boolean_flag, catch_config_error
34 34 from IPython.core.application import BaseIPythonApplication
35 35 from IPython.core.profiledir import ProfileDir
36 36 from IPython.lib.kernel import tunnel_to_kernel, find_connection_file
37 37 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
38 38 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
39 39 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
40 40 from IPython.frontend.qt.console import styles
41 41 from IPython.frontend.qt.console.mainwindow import MainWindow
42 42 from IPython.frontend.qt.kernelmanager import QtKernelManager
43 43 from IPython.utils.path import filefind
44 44 from IPython.utils.py3compat import str_to_bytes
45 45 from IPython.utils.traitlets import (
46 46 Dict, List, Unicode, Integer, CaselessStrEnum, CBool, Any
47 47 )
48 48 from IPython.zmq.ipkernel import IPKernelApp
49 49 from IPython.zmq.session import Session, default_secure
50 50 from IPython.zmq.zmqshell import ZMQInteractiveShell
51 51
52 52 from IPython.frontend.consoleapp import (
53 53 IPythonConsoleApp, app_aliases, app_flags, flags, aliases
54 54 )
55 55
56 56 #-----------------------------------------------------------------------------
57 57 # Network Constants
58 58 #-----------------------------------------------------------------------------
59 59
60 60 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
61 61
62 62 #-----------------------------------------------------------------------------
63 63 # Globals
64 64 #-----------------------------------------------------------------------------
65 65
66 66 _examples = """
67 67 ipython qtconsole # start the qtconsole
68 68 ipython qtconsole --pylab=inline # start with pylab in inline plotting mode
69 69 """
70 70
71 71 #-----------------------------------------------------------------------------
72 72 # Aliases and Flags
73 73 #-----------------------------------------------------------------------------
74 74
75 75 # start with copy of flags
76 76 flags = dict(flags)
77 77 qt_flags = {
78 78 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
79 79 "Use a pure Python kernel instead of an IPython kernel."),
80 80 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
81 81 "Disable rich text support."),
82 82 }
83 83 qt_flags.update(boolean_flag(
84 84 'gui-completion', 'ConsoleWidget.gui_completion',
85 85 "use a GUI widget for tab completion",
86 86 "use plaintext output for completion"
87 87 ))
88 88 # and app_flags from the Console Mixin
89 89 qt_flags.update(app_flags)
90 90 # add frontend flags to the full set
91 91 flags.update(qt_flags)
92 92
93 93 # start with copy of front&backend aliases list
94 94 aliases = dict(aliases)
95 95 qt_aliases = dict(
96 96
97 97 style = 'IPythonWidget.syntax_style',
98 98 stylesheet = 'IPythonQtConsoleApp.stylesheet',
99 99 colors = 'ZMQInteractiveShell.colors',
100 100
101 101 editor = 'IPythonWidget.editor',
102 102 paging = 'ConsoleWidget.paging',
103 103 )
104 104 # and app_aliases from the Console Mixin
105 105 qt_aliases.update(app_aliases)
106 106 # add frontend aliases to the full set
107 107 aliases.update(qt_aliases)
108 108
109 109 # get flags&aliases into sets, and remove a couple that
110 110 # shouldn't be scrubbed from backend flags:
111 111 qt_aliases = set(qt_aliases.keys())
112 112 qt_aliases.remove('colors')
113 113 qt_flags = set(qt_flags.keys())
114 114
115 115 #-----------------------------------------------------------------------------
116 116 # Classes
117 117 #-----------------------------------------------------------------------------
118 118
119 119 #-----------------------------------------------------------------------------
120 120 # IPythonQtConsole
121 121 #-----------------------------------------------------------------------------
122 122
123 123
124 124 class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):
125 125 name = 'ipython-qtconsole'
126 126
127 127 description = """
128 128 The IPython QtConsole.
129 129
130 130 This launches a Console-style application using Qt. It is not a full
131 131 console, in that launched terminal subprocesses will not be able to accept
132 132 input.
133 133
134 134 The QtConsole supports various extra features beyond the Terminal IPython
135 135 shell, such as inline plotting with matplotlib, via:
136 136
137 137 ipython qtconsole --pylab=inline
138 138
139 139 as well as saving your session as HTML, and printing the output.
140 140
141 141 """
142 142 examples = _examples
143 143
144 144 classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir, Session]
145 145 flags = Dict(flags)
146 146 aliases = Dict(aliases)
147 147 frontend_flags = Any(qt_flags)
148 148 frontend_aliases = Any(qt_aliases)
149 149 kernel_manager_class = QtKernelManager
150 150
151 151 stylesheet = Unicode('', config=True,
152 152 help="path to a custom CSS stylesheet")
153 153
154 154 plain = CBool(False, config=True,
155 155 help="Use a plaintext widget instead of rich text (plain can't print/save).")
156 156
157 157 def _pure_changed(self, name, old, new):
158 158 kind = 'plain' if self.plain else 'rich'
159 159 self.config.ConsoleWidget.kind = kind
160 160 if self.pure:
161 161 self.widget_factory = FrontendWidget
162 162 elif self.plain:
163 163 self.widget_factory = IPythonWidget
164 164 else:
165 165 self.widget_factory = RichIPythonWidget
166 166
167 167 _plain_changed = _pure_changed
168 168
169 169 # the factory for creating a widget
170 170 widget_factory = Any(RichIPythonWidget)
171 171
172 172 def parse_command_line(self, argv=None):
173 173 super(IPythonQtConsoleApp, self).parse_command_line(argv)
174 174 self.build_kernel_argv(argv)
175 175
176 176
177 177 def new_frontend_master(self):
178 178 """ Create and return new frontend attached to new kernel, launched on localhost.
179 179 """
180 180 ip = self.ip if self.ip in LOCAL_IPS else LOCALHOST
181 181 kernel_manager = self.kernel_manager_class(
182 182 ip=ip,
183 183 connection_file=self._new_connection_file(),
184 184 config=self.config,
185 185 )
186 186 # start the kernel
187 187 kwargs = dict(ipython=not self.pure)
188 188 kwargs['extra_arguments'] = self.kernel_argv
189 189 kernel_manager.start_kernel(**kwargs)
190 190 kernel_manager.start_channels()
191 191 widget = self.widget_factory(config=self.config,
192 192 local_kernel=True)
193 self.init_colors(widget)
193 194 widget.kernel_manager = kernel_manager
194 195 widget._existing = False
195 196 widget._may_close = True
196 197 widget._confirm_exit = self.confirm_exit
197 198 return widget
198 199
199 200 def new_frontend_slave(self, current_widget):
200 201 """Create and return a new frontend attached to an existing kernel.
201 202
202 203 Parameters
203 204 ----------
204 205 current_widget : IPythonWidget
205 206 The IPythonWidget whose kernel this frontend is to share
206 207 """
207 208 kernel_manager = self.kernel_manager_class(
208 209 connection_file=current_widget.kernel_manager.connection_file,
209 210 config = self.config,
210 211 )
211 212 kernel_manager.load_connection_file()
212 213 kernel_manager.start_channels()
213 214 widget = self.widget_factory(config=self.config,
214 215 local_kernel=False)
216 self.init_colors(widget)
215 217 widget._existing = True
216 218 widget._may_close = False
217 219 widget._confirm_exit = False
218 220 widget.kernel_manager = kernel_manager
219 221 return widget
220 222
221 223 def init_qt_elements(self):
222 224 # Create the widget.
223 225 self.app = QtGui.QApplication([])
224 226
225 227 base_path = os.path.abspath(os.path.dirname(__file__))
226 228 icon_path = os.path.join(base_path, 'resources', 'icon', 'IPythonConsole.svg')
227 229 self.app.icon = QtGui.QIcon(icon_path)
228 230 QtGui.QApplication.setWindowIcon(self.app.icon)
229 231
230 232 local_kernel = (not self.existing) or self.ip in LOCAL_IPS
231 233 self.widget = self.widget_factory(config=self.config,
232 234 local_kernel=local_kernel)
235 self.init_colors(self.widget)
233 236 self.widget._existing = self.existing
234 237 self.widget._may_close = not self.existing
235 238 self.widget._confirm_exit = self.confirm_exit
236 239
237 240 self.widget.kernel_manager = self.kernel_manager
238 241 self.window = MainWindow(self.app,
239 242 confirm_exit=self.confirm_exit,
240 243 new_frontend_factory=self.new_frontend_master,
241 244 slave_frontend_factory=self.new_frontend_slave,
242 245 )
243 246 self.window.log = self.log
244 247 self.window.add_tab_with_frontend(self.widget)
245 248 self.window.init_menu_bar()
246 249
247 250 self.window.setWindowTitle('Python' if self.pure else 'IPython')
248 251
249 def init_colors(self):
252 def init_colors(self, widget):
250 253 """Configure the coloring of the widget"""
251 254 # Note: This will be dramatically simplified when colors
252 255 # are removed from the backend.
253 256
254 257 if self.pure:
255 258 # only IPythonWidget supports styling
256 259 return
257 260
258 261 # parse the colors arg down to current known labels
259 262 try:
260 263 colors = self.config.ZMQInteractiveShell.colors
261 264 except AttributeError:
262 265 colors = None
263 266 try:
264 267 style = self.config.IPythonWidget.syntax_style
265 268 except AttributeError:
266 269 style = None
270 try:
271 sheet = self.config.IPythonWidget.style_sheet
272 except AttributeError:
273 sheet = None
267 274
268 275 # find the value for colors:
269 276 if colors:
270 277 colors=colors.lower()
271 278 if colors in ('lightbg', 'light'):
272 279 colors='lightbg'
273 280 elif colors in ('dark', 'linux'):
274 281 colors='linux'
275 282 else:
276 283 colors='nocolor'
277 284 elif style:
278 285 if style=='bw':
279 286 colors='nocolor'
280 287 elif styles.dark_style(style):
281 288 colors='linux'
282 289 else:
283 290 colors='lightbg'
284 291 else:
285 292 colors=None
286 293
287 # Configure the style.
288 widget = self.widget
294 # Configure the style
289 295 if style:
290 296 widget.style_sheet = styles.sheet_from_template(style, colors)
291 297 widget.syntax_style = style
292 298 widget._syntax_style_changed()
293 299 widget._style_sheet_changed()
294 300 elif colors:
295 # use a default style
301 # use a default dark/light/bw style
296 302 widget.set_default_style(colors=colors)
297 else:
298 # this is redundant for now, but allows the widget's
299 # defaults to change
300 widget.set_default_style()
301 303
302 304 if self.stylesheet:
303 # we got an expicit stylesheet
305 # we got an explicit stylesheet
304 306 if os.path.isfile(self.stylesheet):
305 307 with open(self.stylesheet) as f:
306 308 sheet = f.read()
307 widget.style_sheet = sheet
308 widget._style_sheet_changed()
309 309 else:
310 310 raise IOError("Stylesheet %r not found."%self.stylesheet)
311 if sheet:
312 widget.style_sheet = sheet
313 widget._style_sheet_changed()
314
311 315
312 316 def init_signal(self):
313 317 """allow clean shutdown on sigint"""
314 318 signal.signal(signal.SIGINT, lambda sig, frame: self.exit(-2))
315 319 # need a timer, so that QApplication doesn't block until a real
316 320 # Qt event fires (can require mouse movement)
317 321 # timer trick from http://stackoverflow.com/q/4938723/938949
318 322 timer = QtCore.QTimer()
319 323 # Let the interpreter run each 200 ms:
320 324 timer.timeout.connect(lambda: None)
321 325 timer.start(200)
322 326 # hold onto ref, so the timer doesn't get cleaned up
323 327 self._sigint_timer = timer
324 328
325 329 @catch_config_error
326 330 def initialize(self, argv=None):
327 331 super(IPythonQtConsoleApp, self).initialize(argv)
328 332 IPythonConsoleApp.initialize(self,argv)
329 333 self.init_qt_elements()
330 self.init_colors()
331 334 self.init_signal()
332 335
333 336 def start(self):
334 337
335 338 # draw the window
336 339 self.window.show()
337 340 self.window.raise_()
338 341
339 342 # Start the application main loop.
340 343 self.app.exec_()
341 344
342 345 #-----------------------------------------------------------------------------
343 346 # Main entry point
344 347 #-----------------------------------------------------------------------------
345 348
346 349 def main():
347 350 app = IPythonQtConsoleApp()
348 351 app.initialize()
349 352 app.start()
350 353
351 354
352 355 if __name__ == '__main__':
353 356 main()
General Comments 0
You need to be logged in to leave comments. Login now