##// END OF EJS Templates
QtConsole now uses newapp
MinRK -
Show More
@@ -55,33 +55,39 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
55 55
56 56 #------ Configuration ------------------------------------------------------
57 57
58 # Whether to process ANSI escape codes.
59 ansi_codes = Bool(True, config=True)
60
61 # The maximum number of lines of text before truncation. Specifying a
62 # non-positive number disables text truncation (not recommended).
63 buffer_size = Int(500, config=True)
64
65 # Whether to use a list widget or plain text output for tab completion.
66 gui_completion = Bool(False, config=True)
67
68 # The type of underlying text widget to use. Valid values are 'plain', which
69 # specifies a QPlainTextEdit, and 'rich', which specifies a QTextEdit.
58 ansi_codes = Bool(True, config=True,
59 help="Whether to process ANSI escape codes."
60 )
61 buffer_size = Int(500, config=True,
62 help="""
63 The maximum number of lines of text before truncation. Specifying a
64 non-positive number disables text truncation (not recommended).
65 """
66 )
67 gui_completion = Bool(False, config=True,
68 help="Use a list widget instead of plain text output for tab completion."
69 )
70 70 # NOTE: this value can only be specified during initialization.
71 kind = Enum(['plain', 'rich'], default_value='plain', config=True)
72
73 # The type of paging to use. Valid values are:
74 # 'inside' : The widget pages like a traditional terminal.
75 # 'hsplit' : When paging is requested, the widget is split
76 # horizontally. The top pane contains the console, and the
77 # bottom pane contains the paged text.
78 # 'vsplit' : Similar to 'hsplit', except that a vertical splitter used.
79 # 'custom' : No action is taken by the widget beyond emitting a
80 # 'custom_page_requested(str)' signal.
81 # 'none' : The text is written directly to the console.
71 kind = Enum(['plain', 'rich'], default_value='plain', config=True,
72 help="""
73 The type of underlying text widget to use. Valid values are 'plain', which
74 specifies a QPlainTextEdit, and 'rich', which specifies a QTextEdit.
75 """
76 )
82 77 # NOTE: this value can only be specified during initialization.
83 78 paging = Enum(['inside', 'hsplit', 'vsplit', 'custom', 'none'],
84 default_value='inside', config=True)
79 default_value='inside', config=True,
80 help="""
81 The type of paging to use. Valid values are:
82 'inside' : The widget pages like a traditional terminal.
83 'hsplit' : When paging is requested, the widget is split
84 : horizontally. The top pane contains the console, and the
85 : bottom pane contains the paged text.
86 'vsplit' : Similar to 'hsplit', except that a vertical splitter used.
87 'custom' : No action is taken by the widget beyond emitting a
88 : 'custom_page_requested(str)' signal.
89 'none' : The text is written directly to the console.
90 """)
85 91
86 92 # Whether to override ShortcutEvents for the keybindings defined by this
87 93 # widget (Ctrl+n, Ctrl+a, etc). Enable this if you want this widget to take
@@ -13,7 +13,7 b' from IPython.external.qt import QtCore, QtGui'
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 from IPython.utils.traitlets import Bool
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
@@ -106,6 +106,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
106 106 _ExecutionRequest = namedtuple('_ExecutionRequest', ['id', 'kind'])
107 107 _input_splitter_class = InputSplitter
108 108 _local_kernel = False
109 _highlighter = Instance(FrontendHighlighter)
109 110
110 111 #---------------------------------------------------------------------------
111 112 # 'object' interface
@@ -23,9 +23,7 b' from IPython.core.inputsplitter import IPythonInputSplitter, \\'
23 23 from IPython.core.usage import default_gui_banner
24 24 from IPython.utils.traitlets import Bool, Str, Unicode
25 25 from frontend_widget import FrontendWidget
26 from styles import (default_light_style_sheet, default_light_syntax_style,
27 default_dark_style_sheet, default_dark_syntax_style,
28 default_bw_style_sheet, default_bw_syntax_style)
26 import styles
29 27
30 28 #-----------------------------------------------------------------------------
31 29 # Constants
@@ -56,26 +54,35 b' class IPythonWidget(FrontendWidget):'
56 54 custom_edit = Bool(False)
57 55 custom_edit_requested = QtCore.Signal(object, object)
58 56
59 # 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
61 # be appended to the end the command.
62 editor = Unicode('default', config=True)
63
64 # The editor command to use when a specific line number is requested. The
65 # string should contain two format specifiers: {line} and {filename}. If
66 # this parameter is not specified, the line number option to the %edit magic
67 # will be ignored.
68 editor_line = Unicode(config=True)
69
70 # A CSS stylesheet. The stylesheet can contain classes for:
71 # 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
72 # 2. Pygments: .c, .k, .o, etc (see PygmentsHighlighter)
73 # 3. IPython: .error, .in-prompt, .out-prompt, etc
74 style_sheet = Unicode(config=True)
57 editor = Unicode('default', config=True,
58 help="""
59 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
61 be appended to the end the command.
62 """)
63
64 editor_line = Unicode(config=True,
65 help="""
66 The editor command to use when a specific line number is requested. The
67 string should contain two format specifiers: {line} and {filename}. If
68 this parameter is not specified, the line number option to the %edit magic
69 will be ignored.
70 """)
71
72 style_sheet = Unicode(config=True,
73 help="""
74 A CSS stylesheet. The stylesheet can contain classes for:
75 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
76 2. Pygments: .c, .k, .o, etc. (see PygmentsHighlighter)
77 3. IPython: .error, .in-prompt, .out-prompt, etc
78 """)
75 79
76 # If not empty, use this Pygments style for syntax highlighting. Otherwise,
77 # the style sheet is queried for Pygments style information.
78 syntax_style = Str(config=True)
80
81 syntax_style = Str(config=True,
82 help="""
83 If not empty, use this Pygments style for syntax highlighting. Otherwise,
84 the style sheet is queried for Pygments style information.
85 """)
79 86
80 87 # Prompts.
81 88 in_prompt = Str(default_in_prompt, config=True)
@@ -371,14 +378,14 b' class IPythonWidget(FrontendWidget):'
371 378 """
372 379 colors = colors.lower()
373 380 if colors=='lightbg':
374 self.style_sheet = default_light_style_sheet
375 self.syntax_style = default_light_syntax_style
381 self.style_sheet = styles.default_light_style_sheet
382 self.syntax_style = styles.default_light_syntax_style
376 383 elif colors=='linux':
377 self.style_sheet = default_dark_style_sheet
378 self.syntax_style = default_dark_syntax_style
384 self.style_sheet = styles.default_dark_style_sheet
385 self.syntax_style = styles.default_dark_syntax_style
379 386 elif colors=='nocolor':
380 self.style_sheet = default_bw_style_sheet
381 self.syntax_style = default_bw_syntax_style
387 self.style_sheet = styles.default_bw_style_sheet
388 self.syntax_style = styles.default_bw_syntax_style
382 389 else:
383 390 raise KeyError("No such color scheme: %s"%colors)
384 391
@@ -482,9 +489,13 b' class IPythonWidget(FrontendWidget):'
482 489 bg_color = self._control.palette().window().color()
483 490 self._ansi_processor.set_background_color(bg_color)
484 491
492
485 493 def _syntax_style_changed(self):
486 494 """ Set the style for the syntax highlighter.
487 495 """
496 if self._highlighter is None:
497 # ignore premature calls
498 return
488 499 if self.syntax_style:
489 500 self._highlighter.set_style(self.syntax_style)
490 501 else:
@@ -5,17 +5,32 b''
5 5 # Imports
6 6 #-----------------------------------------------------------------------------
7 7
8 # Systemm library imports
8 # stdlib imports
9 import os
10 import signal
11 import sys
12
13 # System library imports
9 14 from IPython.external.qt import QtGui
10 15 from pygments.styles import get_all_styles
11 16
12 17 # Local imports
13 from IPython.external.argparse import ArgumentParser
18 from IPython.core.newapplication import ProfileDir, BaseIPythonApplication
14 19 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
15 20 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
16 21 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
17 22 from IPython.frontend.qt.console import styles
18 23 from IPython.frontend.qt.kernelmanager import QtKernelManager
24 from IPython.utils.traitlets import (
25 Dict, List, Unicode, Int, CaselessStrEnum, Bool, Any
26 )
27 from IPython.zmq.ipkernel import (
28 flags as ipkernel_flags,
29 aliases as ipkernel_aliases,
30 IPKernelApp
31 )
32 from IPython.zmq.zmqshell import ZMQInteractiveShell
33
19 34
20 35 #-----------------------------------------------------------------------------
21 36 # Network Constants
@@ -127,126 +142,188 b' class MainWindow(QtGui.QMainWindow):'
127 142 event.accept()
128 143
129 144 #-----------------------------------------------------------------------------
130 # Main entry point
145 # Aliases and Flags
131 146 #-----------------------------------------------------------------------------
132 147
133 def main():
134 """ Entry point for application.
135 """
136 # Parse command line arguments.
137 parser = ArgumentParser()
138 kgroup = parser.add_argument_group('kernel options')
139 kgroup.add_argument('-e', '--existing', action='store_true',
140 help='connect to an existing kernel')
141 kgroup.add_argument('--ip', type=str, default=LOCALHOST,
142 help=\
143 "set the kernel\'s IP address [default localhost].\
144 If the IP address is something other than localhost, then \
145 Consoles on other machines will be able to connect\
146 to the Kernel, so be careful!")
147 kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
148 help='set the XREQ channel port [default random]')
149 kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
150 help='set the SUB channel port [default random]')
151 kgroup.add_argument('--rep', type=int, metavar='PORT', default=0,
152 help='set the REP channel port [default random]')
153 kgroup.add_argument('--hb', type=int, metavar='PORT', default=0,
154 help='set the heartbeat port [default random]')
155
156 egroup = kgroup.add_mutually_exclusive_group()
157 egroup.add_argument('--pure', action='store_true', help = \
158 'use a pure Python kernel instead of an IPython kernel')
159 egroup.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
160 const='auto', help = \
161 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
162 given, the GUI backend is matplotlib's, otherwise use one of: \
163 ['tk', 'gtk', 'qt', 'wx', 'inline'].")
164
165 wgroup = parser.add_argument_group('widget options')
166 wgroup.add_argument('--paging', type=str, default='inside',
167 choices = ['inside', 'hsplit', 'vsplit', 'none'],
168 help='set the paging style [default inside]')
169 wgroup.add_argument('--plain', action='store_true',
170 help='disable rich text support')
171 wgroup.add_argument('--gui-completion', action='store_true',
172 help='use a GUI widget for tab completion')
173 wgroup.add_argument('--style', type=str,
174 choices = list(get_all_styles()),
175 help='specify a pygments style for by name')
176 wgroup.add_argument('--stylesheet', type=str,
177 help='path to a custom CSS stylesheet')
178 wgroup.add_argument('--colors', type=str, help = \
179 "Set the color scheme (LightBG,Linux,NoColor). This is guessed \
180 based on the pygments style if not set.")
181
182 args = parser.parse_args()
183
184 # parse the colors arg down to current known labels
185 if args.colors:
186 colors=args.colors.lower()
187 if colors in ('lightbg', 'light'):
188 colors='lightbg'
189 elif colors in ('dark', 'linux'):
190 colors='linux'
191 else:
192 colors='nocolor'
193 elif args.style:
194 if args.style=='bw':
195 colors='nocolor'
196 elif styles.dark_style(args.style):
197 colors='linux'
148 flags = dict(ipkernel_flags)
149
150 flags.update({
151 'existing' : ({'IPythonQtConsoleApp' : {'existing' : True}},
152 "Connect to an existing kernel."),
153 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
154 "Use a pure Python kernel instead of an IPython kernel."),
155 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
156 "Disable rich text support."),
157 'gui-completion' : ({'FrontendWidget' : {'gui_completion' : True}},
158 "use a GUI widget for tab completion"),
159 })
160
161 qt_flags = ['existing', 'pure', 'plain', 'gui-completion']
162
163 aliases = dict(ipkernel_aliases)
164
165 aliases.update(dict(
166 hb = 'IPythonQtConsoleApp.hb_port',
167 shell = 'IPythonQtConsoleApp.shell_port',
168 iopub = 'IPythonQtConsoleApp.iopub_port',
169 stdin = 'IPythonQtConsoleApp.stdin_port',
170 ip = 'IPythonQtConsoleApp.ip',
171
172 plain = 'IPythonQtConsoleApp.plain',
173 pure = 'IPythonQtConsoleApp.pure',
174 gui_completion = 'FrontendWidget.gui_completion',
175 style = 'IPythonWidget.syntax_style',
176 stylesheet = 'IPythonQtConsoleApp.stylesheet',
177 colors = 'ZMQInteractiveShell.colors',
178
179 editor = 'IPythonWidget.editor',
180 pi = 'IPythonWidget.in_prompt',
181 po = 'IPythonWidget.out_prompt',
182 si = 'IPythonWidget.input_sep',
183 so = 'IPythonWidget.output_sep',
184 so2 = 'IPythonWidget.output_sep2',
185 ))
186
187 #-----------------------------------------------------------------------------
188 # IPythonQtConsole
189 #-----------------------------------------------------------------------------
190
191 class IPythonQtConsoleApp(BaseIPythonApplication):
192 name = 'ipython-qtconsole'
193 default_config_file_name='ipython_config.py'
194 classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir]
195 flags = Dict(flags)
196 aliases = Dict(aliases)
197
198 kernel_argv = List(Unicode)
199
200 # connection info:
201 ip = Unicode(LOCALHOST, config=True,
202 help="""Set the kernel\'s IP address [default localhost].
203 If the IP address is something other than localhost, then
204 Consoles on other machines will be able to connect
205 to the Kernel, so be careful!"""
206 )
207 hb_port = Int(0, config=True,
208 help="set the heartbeat port [default: random]")
209 shell_port = Int(0, config=True,
210 help="set the shell (XREP) port [default: random]")
211 iopub_port = Int(0, config=True,
212 help="set the iopub (PUB) port [default: random]")
213 stdin_port = Int(0, config=True,
214 help="set the stdin (XREQ) port [default: random]")
215
216 existing = Bool(False, config=True,
217 help="Whether to connect to an already running Kernel.")
218
219 stylesheet = Unicode('', config=True,
220 help="path to a custom CSS stylesheet")
221
222 pure = Bool(False, config=True,
223 help="Use a pure Python kernel instead of an IPython kernel.")
224 plain = Bool(False, config=True,
225 help="Use a pure Python kernel instead of an IPython kernel.")
226
227 def _pure_changed(self, name, old, new):
228 kind = 'plain' if self.plain else 'rich'
229 self.config.ConsoleWidget.kind = kind
230 if self.pure:
231 self.widget_factory = FrontendWidget
232 elif self.plain:
233 self.widget_factory = IPythonWidget
198 234 else:
199 colors='lightbg'
200 else:
201 colors=None
202
203 # Don't let Qt or ZMQ swallow KeyboardInterupts.
204 import signal
205 signal.signal(signal.SIGINT, signal.SIG_DFL)
206
207 # Create a KernelManager and start a kernel.
208 kernel_manager = QtKernelManager(xreq_address=(args.ip, args.xreq),
209 sub_address=(args.ip, args.sub),
210 rep_address=(args.ip, args.rep),
211 hb_address=(args.ip, args.hb))
212 if not args.existing:
213 # if not args.ip in LOCAL_IPS+ALL_ALIAS:
214 # raise ValueError("Must bind a local ip, such as: %s"%LOCAL_IPS)
215
216 kwargs = dict(ip=args.ip)
217 if args.pure:
218 kwargs['ipython']=False
235 self.widget_factory = RichIPythonWidget
236
237 _plain_changed = _pure_changed
238
239 # the factory for creating a widget
240 widget_factory = Any(RichIPythonWidget)
241
242 def parse_command_line(self, argv=None):
243 super(IPythonQtConsoleApp, self).parse_command_line(argv)
244 if argv is None:
245 argv = sys.argv[1:]
246
247 self.kernel_argv = list(argv) # copy
248
249 # scrub frontend-specific flags
250 for a in argv:
251 if a.startswith('--') and a[2:] in qt_flags:
252 self.kernel_argv.remove(a)
253
254 def init_kernel_manager(self):
255 # Don't let Qt or ZMQ swallow KeyboardInterupts.
256 signal.signal(signal.SIGINT, signal.SIG_DFL)
257
258 # Create a KernelManager and start a kernel.
259 self.kernel_manager = QtKernelManager(
260 xreq_address=(self.ip, self.shell_port),
261 sub_address=(self.ip, self.iopub_port),
262 rep_address=(self.ip, self.stdin_port),
263 hb_address=(self.ip, self.hb_port)
264 )
265 # start the kernel
266 if not self.existing:
267 kwargs = dict(ip=self.ip, ipython=not self.pure)
268 kwargs['extra_arguments'] = self.kernel_argv
269 self.kernel_manager.start_kernel(**kwargs)
270 self.kernel_manager.start_channels()
271
272
273 def init_qt_elements(self):
274 # Create the widget.
275 self.app = QtGui.QApplication([])
276 local_kernel = (not self.existing) or self.ip in LOCAL_IPS
277 self.widget = self.widget_factory(config=self.config,
278 local_kernel=local_kernel)
279 self.widget.kernel_manager = self.kernel_manager
280 self.window = MainWindow(self.app, self.widget, self.existing,
281 may_close=local_kernel)
282 self.window.setWindowTitle('Python' if self.pure else 'IPython')
283
284 def init_colors(self):
285 """Configure the coloring of the widget"""
286 # Note: This will be dramatically simplified when colors
287 # are removed from the backend.
288
289 if self.pure:
290 # only IPythonWidget supports styling
291 return
292
293 # parse the colors arg down to current known labels
294 try:
295 colors = self.config.ZMQInteractiveShell.colors
296 except AttributeError:
297 colors = None
298 try:
299 style = self.config.IPythonWidget.colors
300 except AttributeError:
301 style = None
302
303 # find the value for colors:
304 if colors:
305 colors=colors.lower()
306 if colors in ('lightbg', 'light'):
307 colors='lightbg'
308 elif colors in ('dark', 'linux'):
309 colors='linux'
310 else:
311 colors='nocolor'
312 elif style:
313 if style=='bw':
314 colors='nocolor'
315 elif styles.dark_style(style):
316 colors='linux'
317 else:
318 colors='lightbg'
219 319 else:
220 extra = []
221 if colors:
222 extra.append("colors=%s"%colors)
223 if args.pylab:
224 extra.append("pylab=%s"%args.pylab)
225 kwargs['extra_arguments'] = extra
226
227 kernel_manager.start_kernel(**kwargs)
228 kernel_manager.start_channels()
229
230 # Create the widget.
231 app = QtGui.QApplication([])
232 local_kernel = (not args.existing) or args.ip in LOCAL_IPS
233 if args.pure:
234 kind = 'plain' if args.plain else 'rich'
235 widget = FrontendWidget(kind=kind, paging=args.paging,
236 local_kernel=local_kernel)
237 elif args.plain:
238 widget = IPythonWidget(paging=args.paging, local_kernel=local_kernel)
239 else:
240 widget = RichIPythonWidget(paging=args.paging,
241 local_kernel=local_kernel)
242 widget.gui_completion = args.gui_completion
243 widget.kernel_manager = kernel_manager
244
245 # Configure the style.
246 if not args.pure: # only IPythonWidget supports styles
247 if args.style:
248 widget.syntax_style = args.style
249 widget.style_sheet = styles.sheet_from_template(args.style, colors)
320 colors=None
321
322 # Configure the style.
323 widget = self.widget
324 if style:
325 widget.style_sheet = styles.sheet_from_template(style, colors)
326 widget.syntax_style = style
250 327 widget._syntax_style_changed()
251 328 widget._style_sheet_changed()
252 329 elif colors:
@@ -257,23 +334,38 b' def main():'
257 334 # defaults to change
258 335 widget.set_default_style()
259 336
260 if args.stylesheet:
337 if self.stylesheet:
261 338 # we got an expicit stylesheet
262 if os.path.isfile(args.stylesheet):
263 with open(args.stylesheet) as f:
339 if os.path.isfile(self.stylesheet):
340 with open(self.stylesheet) as f:
264 341 sheet = f.read()
265 342 widget.style_sheet = sheet
266 343 widget._style_sheet_changed()
267 344 else:
268 raise IOError("Stylesheet %r not found."%args.stylesheet)
345 raise IOError("Stylesheet %r not found."%self.stylesheet)
346
347 def initialize(self, argv=None):
348 super(IPythonQtConsoleApp, self).initialize(argv)
349 self.init_kernel_manager()
350 self.init_qt_elements()
351 self.init_colors()
352
353 def start(self):
354
355 # draw the window
356 self.window.show()
269 357
270 # Create the main window.
271 window = MainWindow(app, widget, args.existing, may_close=local_kernel)
272 window.setWindowTitle('Python' if args.pure else 'IPython')
273 window.show()
358 # Start the application main loop.
359 self.app.exec_()
274 360
275 # Start the application main loop.
276 app.exec_()
361 #-----------------------------------------------------------------------------
362 # Main entry point
363 #-----------------------------------------------------------------------------
364
365 def main():
366 app = IPythonQtConsoleApp()
367 app.initialize()
368 app.start()
277 369
278 370
279 371 if __name__ == '__main__':
General Comments 0
You need to be logged in to leave comments. Login now