##// END OF EJS Templates
Add flag for simple_prompt....
Matthias Bussonnier -
Show More
@@ -0,0 +1,4 b''
1 when using IPython as a subprocess, like for emacs inferior-shell, IPython can
2 be started with --simple-prompt flag, which will bypass the prompt_toolkit
3 input layer. In this mode completion, prompt color and many other features are
4 disabled.
@@ -1,371 +1,376 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~IPython.core.application.Application` object for the command
4 The :class:`~IPython.core.application.Application` object for the command
5 line :command:`ipython` program.
5 line :command:`ipython` program.
6 """
6 """
7
7
8 # Copyright (c) IPython Development Team.
8 # Copyright (c) IPython Development Team.
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10
10
11 from __future__ import absolute_import
11 from __future__ import absolute_import
12 from __future__ import print_function
12 from __future__ import print_function
13
13
14 import logging
14 import logging
15 import os
15 import os
16 import sys
16 import sys
17 import warnings
17 import warnings
18
18
19 from traitlets.config.loader import Config
19 from traitlets.config.loader import Config
20 from traitlets.config.application import boolean_flag, catch_config_error, Application
20 from traitlets.config.application import boolean_flag, catch_config_error, Application
21 from IPython.core import release
21 from IPython.core import release
22 from IPython.core import usage
22 from IPython.core import usage
23 from IPython.core.completer import IPCompleter
23 from IPython.core.completer import IPCompleter
24 from IPython.core.crashhandler import CrashHandler
24 from IPython.core.crashhandler import CrashHandler
25 from IPython.core.formatters import PlainTextFormatter
25 from IPython.core.formatters import PlainTextFormatter
26 from IPython.core.history import HistoryManager
26 from IPython.core.history import HistoryManager
27 from IPython.core.prompts import PromptManager
27 from IPython.core.prompts import PromptManager
28 from IPython.core.application import (
28 from IPython.core.application import (
29 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
29 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
30 )
30 )
31 from IPython.core.magics import ScriptMagics
31 from IPython.core.magics import ScriptMagics
32 from IPython.core.shellapp import (
32 from IPython.core.shellapp import (
33 InteractiveShellApp, shell_flags, shell_aliases
33 InteractiveShellApp, shell_flags, shell_aliases
34 )
34 )
35 from IPython.extensions.storemagic import StoreMagics
35 from IPython.extensions.storemagic import StoreMagics
36 from .ptshell import TerminalInteractiveShell
36 from .ptshell import TerminalInteractiveShell
37 from IPython.paths import get_ipython_dir
37 from IPython.paths import get_ipython_dir
38 from traitlets import (
38 from traitlets import (
39 Bool, List, Dict, default, observe,
39 Bool, List, Dict, default, observe,
40 )
40 )
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Globals, utilities and helpers
43 # Globals, utilities and helpers
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 _examples = """
46 _examples = """
47 ipython --matplotlib # enable matplotlib integration
47 ipython --matplotlib # enable matplotlib integration
48 ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
48 ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
49
49
50 ipython --log-level=DEBUG # set logging to DEBUG
50 ipython --log-level=DEBUG # set logging to DEBUG
51 ipython --profile=foo # start with profile foo
51 ipython --profile=foo # start with profile foo
52
52
53 ipython profile create foo # create profile foo w/ default config files
53 ipython profile create foo # create profile foo w/ default config files
54 ipython help profile # show the help for the profile subcmd
54 ipython help profile # show the help for the profile subcmd
55
55
56 ipython locate # print the path to the IPython directory
56 ipython locate # print the path to the IPython directory
57 ipython locate profile foo # print the path to the directory for profile `foo`
57 ipython locate profile foo # print the path to the directory for profile `foo`
58 """
58 """
59
59
60 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
61 # Crash handler for this application
61 # Crash handler for this application
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63
63
64 class IPAppCrashHandler(CrashHandler):
64 class IPAppCrashHandler(CrashHandler):
65 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
65 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
66
66
67 def __init__(self, app):
67 def __init__(self, app):
68 contact_name = release.author
68 contact_name = release.author
69 contact_email = release.author_email
69 contact_email = release.author_email
70 bug_tracker = 'https://github.com/ipython/ipython/issues'
70 bug_tracker = 'https://github.com/ipython/ipython/issues'
71 super(IPAppCrashHandler,self).__init__(
71 super(IPAppCrashHandler,self).__init__(
72 app, contact_name, contact_email, bug_tracker
72 app, contact_name, contact_email, bug_tracker
73 )
73 )
74
74
75 def make_report(self,traceback):
75 def make_report(self,traceback):
76 """Return a string containing a crash report."""
76 """Return a string containing a crash report."""
77
77
78 sec_sep = self.section_sep
78 sec_sep = self.section_sep
79 # Start with parent report
79 # Start with parent report
80 report = [super(IPAppCrashHandler, self).make_report(traceback)]
80 report = [super(IPAppCrashHandler, self).make_report(traceback)]
81 # Add interactive-specific info we may have
81 # Add interactive-specific info we may have
82 rpt_add = report.append
82 rpt_add = report.append
83 try:
83 try:
84 rpt_add(sec_sep+"History of session input:")
84 rpt_add(sec_sep+"History of session input:")
85 for line in self.app.shell.user_ns['_ih']:
85 for line in self.app.shell.user_ns['_ih']:
86 rpt_add(line)
86 rpt_add(line)
87 rpt_add('\n*** Last line of input (may not be in above history):\n')
87 rpt_add('\n*** Last line of input (may not be in above history):\n')
88 rpt_add(self.app.shell._last_input_line+'\n')
88 rpt_add(self.app.shell._last_input_line+'\n')
89 except:
89 except:
90 pass
90 pass
91
91
92 return ''.join(report)
92 return ''.join(report)
93
93
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95 # Aliases and Flags
95 # Aliases and Flags
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97 flags = dict(base_flags)
97 flags = dict(base_flags)
98 flags.update(shell_flags)
98 flags.update(shell_flags)
99 frontend_flags = {}
99 frontend_flags = {}
100 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
100 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
101 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
101 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
102 'Turn on auto editing of files with syntax errors.',
102 'Turn on auto editing of files with syntax errors.',
103 'Turn off auto editing of files with syntax errors.'
103 'Turn off auto editing of files with syntax errors.'
104 )
104 )
105 addflag('simple-prompt', 'TerminalInteractiveShell.simple_prompt',
106 "Force simple minimal prompt using `raw_input`",
107 "Use a rich interactive prompt with prompt_toolkit",
108 )
109
105 addflag('banner', 'TerminalIPythonApp.display_banner',
110 addflag('banner', 'TerminalIPythonApp.display_banner',
106 "Display a banner upon starting IPython.",
111 "Display a banner upon starting IPython.",
107 "Don't display a banner upon starting IPython."
112 "Don't display a banner upon starting IPython."
108 )
113 )
109 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
114 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
110 """Set to confirm when you try to exit IPython with an EOF (Control-D
115 """Set to confirm when you try to exit IPython with an EOF (Control-D
111 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
116 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
112 you can force a direct exit without any confirmation.""",
117 you can force a direct exit without any confirmation.""",
113 "Don't prompt the user when exiting."
118 "Don't prompt the user when exiting."
114 )
119 )
115 addflag('term-title', 'TerminalInteractiveShell.term_title',
120 addflag('term-title', 'TerminalInteractiveShell.term_title',
116 "Enable auto setting the terminal title.",
121 "Enable auto setting the terminal title.",
117 "Disable auto setting the terminal title."
122 "Disable auto setting the terminal title."
118 )
123 )
119 classic_config = Config()
124 classic_config = Config()
120 classic_config.InteractiveShell.cache_size = 0
125 classic_config.InteractiveShell.cache_size = 0
121 classic_config.PlainTextFormatter.pprint = False
126 classic_config.PlainTextFormatter.pprint = False
122 classic_config.PromptManager.in_template = '>>> '
127 classic_config.PromptManager.in_template = '>>> '
123 classic_config.PromptManager.in2_template = '... '
128 classic_config.PromptManager.in2_template = '... '
124 classic_config.PromptManager.out_template = ''
129 classic_config.PromptManager.out_template = ''
125 classic_config.InteractiveShell.separate_in = ''
130 classic_config.InteractiveShell.separate_in = ''
126 classic_config.InteractiveShell.separate_out = ''
131 classic_config.InteractiveShell.separate_out = ''
127 classic_config.InteractiveShell.separate_out2 = ''
132 classic_config.InteractiveShell.separate_out2 = ''
128 classic_config.InteractiveShell.colors = 'NoColor'
133 classic_config.InteractiveShell.colors = 'NoColor'
129 classic_config.InteractiveShell.xmode = 'Plain'
134 classic_config.InteractiveShell.xmode = 'Plain'
130
135
131 frontend_flags['classic']=(
136 frontend_flags['classic']=(
132 classic_config,
137 classic_config,
133 "Gives IPython a similar feel to the classic Python prompt."
138 "Gives IPython a similar feel to the classic Python prompt."
134 )
139 )
135 # # log doesn't make so much sense this way anymore
140 # # log doesn't make so much sense this way anymore
136 # paa('--log','-l',
141 # paa('--log','-l',
137 # action='store_true', dest='InteractiveShell.logstart',
142 # action='store_true', dest='InteractiveShell.logstart',
138 # help="Start logging to the default log file (./ipython_log.py).")
143 # help="Start logging to the default log file (./ipython_log.py).")
139 #
144 #
140 # # quick is harder to implement
145 # # quick is harder to implement
141 frontend_flags['quick']=(
146 frontend_flags['quick']=(
142 {'TerminalIPythonApp' : {'quick' : True}},
147 {'TerminalIPythonApp' : {'quick' : True}},
143 "Enable quick startup with no config files."
148 "Enable quick startup with no config files."
144 )
149 )
145
150
146 frontend_flags['i'] = (
151 frontend_flags['i'] = (
147 {'TerminalIPythonApp' : {'force_interact' : True}},
152 {'TerminalIPythonApp' : {'force_interact' : True}},
148 """If running code from the command line, become interactive afterwards.
153 """If running code from the command line, become interactive afterwards.
149 It is often useful to follow this with `--` to treat remaining flags as
154 It is often useful to follow this with `--` to treat remaining flags as
150 script arguments.
155 script arguments.
151 """
156 """
152 )
157 )
153 flags.update(frontend_flags)
158 flags.update(frontend_flags)
154
159
155 aliases = dict(base_aliases)
160 aliases = dict(base_aliases)
156 aliases.update(shell_aliases)
161 aliases.update(shell_aliases)
157
162
158 #-----------------------------------------------------------------------------
163 #-----------------------------------------------------------------------------
159 # Main classes and functions
164 # Main classes and functions
160 #-----------------------------------------------------------------------------
165 #-----------------------------------------------------------------------------
161
166
162
167
163 class LocateIPythonApp(BaseIPythonApplication):
168 class LocateIPythonApp(BaseIPythonApplication):
164 description = """print the path to the IPython dir"""
169 description = """print the path to the IPython dir"""
165 subcommands = Dict(dict(
170 subcommands = Dict(dict(
166 profile=('IPython.core.profileapp.ProfileLocate',
171 profile=('IPython.core.profileapp.ProfileLocate',
167 "print the path to an IPython profile directory",
172 "print the path to an IPython profile directory",
168 ),
173 ),
169 ))
174 ))
170 def start(self):
175 def start(self):
171 if self.subapp is not None:
176 if self.subapp is not None:
172 return self.subapp.start()
177 return self.subapp.start()
173 else:
178 else:
174 print(self.ipython_dir)
179 print(self.ipython_dir)
175
180
176
181
177 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
182 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
178 name = u'ipython'
183 name = u'ipython'
179 description = usage.cl_usage
184 description = usage.cl_usage
180 crash_handler_class = IPAppCrashHandler
185 crash_handler_class = IPAppCrashHandler
181 examples = _examples
186 examples = _examples
182
187
183 flags = Dict(flags)
188 flags = Dict(flags)
184 aliases = Dict(aliases)
189 aliases = Dict(aliases)
185 classes = List()
190 classes = List()
186 @default('classes')
191 @default('classes')
187 def _classes_default(self):
192 def _classes_default(self):
188 """This has to be in a method, for TerminalIPythonApp to be available."""
193 """This has to be in a method, for TerminalIPythonApp to be available."""
189 return [
194 return [
190 InteractiveShellApp, # ShellApp comes before TerminalApp, because
195 InteractiveShellApp, # ShellApp comes before TerminalApp, because
191 self.__class__, # it will also affect subclasses (e.g. QtConsole)
196 self.__class__, # it will also affect subclasses (e.g. QtConsole)
192 TerminalInteractiveShell,
197 TerminalInteractiveShell,
193 PromptManager,
198 PromptManager,
194 HistoryManager,
199 HistoryManager,
195 ProfileDir,
200 ProfileDir,
196 PlainTextFormatter,
201 PlainTextFormatter,
197 IPCompleter,
202 IPCompleter,
198 ScriptMagics,
203 ScriptMagics,
199 StoreMagics,
204 StoreMagics,
200 ]
205 ]
201
206
202 deprecated_subcommands = dict(
207 deprecated_subcommands = dict(
203 qtconsole=('qtconsole.qtconsoleapp.JupyterQtConsoleApp',
208 qtconsole=('qtconsole.qtconsoleapp.JupyterQtConsoleApp',
204 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter Qt Console."""
209 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter Qt Console."""
205 ),
210 ),
206 notebook=('notebook.notebookapp.NotebookApp',
211 notebook=('notebook.notebookapp.NotebookApp',
207 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter HTML Notebook Server."""
212 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter HTML Notebook Server."""
208 ),
213 ),
209 console=('jupyter_console.app.ZMQTerminalIPythonApp',
214 console=('jupyter_console.app.ZMQTerminalIPythonApp',
210 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter terminal-based Console."""
215 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter terminal-based Console."""
211 ),
216 ),
212 nbconvert=('nbconvert.nbconvertapp.NbConvertApp',
217 nbconvert=('nbconvert.nbconvertapp.NbConvertApp',
213 "DEPRECATED, Will be removed in IPython 6.0 : Convert notebooks to/from other formats."
218 "DEPRECATED, Will be removed in IPython 6.0 : Convert notebooks to/from other formats."
214 ),
219 ),
215 trust=('nbformat.sign.TrustNotebookApp',
220 trust=('nbformat.sign.TrustNotebookApp',
216 "DEPRECATED, Will be removed in IPython 6.0 : Sign notebooks to trust their potentially unsafe contents at load."
221 "DEPRECATED, Will be removed in IPython 6.0 : Sign notebooks to trust their potentially unsafe contents at load."
217 ),
222 ),
218 kernelspec=('jupyter_client.kernelspecapp.KernelSpecApp',
223 kernelspec=('jupyter_client.kernelspecapp.KernelSpecApp',
219 "DEPRECATED, Will be removed in IPython 6.0 : Manage Jupyter kernel specifications."
224 "DEPRECATED, Will be removed in IPython 6.0 : Manage Jupyter kernel specifications."
220 ),
225 ),
221 )
226 )
222 subcommands = dict(
227 subcommands = dict(
223 profile = ("IPython.core.profileapp.ProfileApp",
228 profile = ("IPython.core.profileapp.ProfileApp",
224 "Create and manage IPython profiles."
229 "Create and manage IPython profiles."
225 ),
230 ),
226 kernel = ("ipykernel.kernelapp.IPKernelApp",
231 kernel = ("ipykernel.kernelapp.IPKernelApp",
227 "Start a kernel without an attached frontend."
232 "Start a kernel without an attached frontend."
228 ),
233 ),
229 locate=('IPython.terminal.ipapp.LocateIPythonApp',
234 locate=('IPython.terminal.ipapp.LocateIPythonApp',
230 LocateIPythonApp.description
235 LocateIPythonApp.description
231 ),
236 ),
232 history=('IPython.core.historyapp.HistoryApp',
237 history=('IPython.core.historyapp.HistoryApp',
233 "Manage the IPython history database."
238 "Manage the IPython history database."
234 ),
239 ),
235 )
240 )
236 deprecated_subcommands['install-nbextension'] = (
241 deprecated_subcommands['install-nbextension'] = (
237 "notebook.nbextensions.InstallNBExtensionApp",
242 "notebook.nbextensions.InstallNBExtensionApp",
238 "DEPRECATED, Will be removed in IPython 6.0 : Install Jupyter notebook extension files"
243 "DEPRECATED, Will be removed in IPython 6.0 : Install Jupyter notebook extension files"
239 )
244 )
240 subcommands.update(deprecated_subcommands)
245 subcommands.update(deprecated_subcommands)
241
246
242 # *do* autocreate requested profile, but don't create the config file.
247 # *do* autocreate requested profile, but don't create the config file.
243 auto_create=Bool(True)
248 auto_create=Bool(True)
244 # configurables
249 # configurables
245 quick = Bool(False,
250 quick = Bool(False,
246 help="""Start IPython quickly by skipping the loading of config files."""
251 help="""Start IPython quickly by skipping the loading of config files."""
247 ).tag(config=True)
252 ).tag(config=True)
248 @observe('quick')
253 @observe('quick')
249 def _quick_changed(self, change):
254 def _quick_changed(self, change):
250 if change['new']:
255 if change['new']:
251 self.load_config_file = lambda *a, **kw: None
256 self.load_config_file = lambda *a, **kw: None
252
257
253 display_banner = Bool(True,
258 display_banner = Bool(True,
254 help="Whether to display a banner upon starting IPython."
259 help="Whether to display a banner upon starting IPython."
255 ).tag(config=True)
260 ).tag(config=True)
256
261
257 # if there is code of files to run from the cmd line, don't interact
262 # if there is code of files to run from the cmd line, don't interact
258 # unless the --i flag (App.force_interact) is true.
263 # unless the --i flag (App.force_interact) is true.
259 force_interact = Bool(False,
264 force_interact = Bool(False,
260 help="""If a command or file is given via the command-line,
265 help="""If a command or file is given via the command-line,
261 e.g. 'ipython foo.py', start an interactive shell after executing the
266 e.g. 'ipython foo.py', start an interactive shell after executing the
262 file or command."""
267 file or command."""
263 ).tag(config=True)
268 ).tag(config=True)
264 @observe('force_interact')
269 @observe('force_interact')
265 def _force_interact_changed(self, change):
270 def _force_interact_changed(self, change):
266 if change['new']:
271 if change['new']:
267 self.interact = True
272 self.interact = True
268
273
269 @observe('file_to_run', 'code_to_run', 'module_to_run')
274 @observe('file_to_run', 'code_to_run', 'module_to_run')
270 def _file_to_run_changed(self, change):
275 def _file_to_run_changed(self, change):
271 new = change['new']
276 new = change['new']
272 if new:
277 if new:
273 self.something_to_run = True
278 self.something_to_run = True
274 if new and not self.force_interact:
279 if new and not self.force_interact:
275 self.interact = False
280 self.interact = False
276
281
277 # internal, not-configurable
282 # internal, not-configurable
278 something_to_run=Bool(False)
283 something_to_run=Bool(False)
279
284
280 def parse_command_line(self, argv=None):
285 def parse_command_line(self, argv=None):
281 """override to allow old '-pylab' flag with deprecation warning"""
286 """override to allow old '-pylab' flag with deprecation warning"""
282
287
283 argv = sys.argv[1:] if argv is None else argv
288 argv = sys.argv[1:] if argv is None else argv
284
289
285 if '-pylab' in argv:
290 if '-pylab' in argv:
286 # deprecated `-pylab` given,
291 # deprecated `-pylab` given,
287 # warn and transform into current syntax
292 # warn and transform into current syntax
288 argv = argv[:] # copy, don't clobber
293 argv = argv[:] # copy, don't clobber
289 idx = argv.index('-pylab')
294 idx = argv.index('-pylab')
290 warnings.warn("`-pylab` flag has been deprecated.\n"
295 warnings.warn("`-pylab` flag has been deprecated.\n"
291 " Use `--matplotlib <backend>` and import pylab manually.")
296 " Use `--matplotlib <backend>` and import pylab manually.")
292 argv[idx] = '--pylab'
297 argv[idx] = '--pylab'
293
298
294 return super(TerminalIPythonApp, self).parse_command_line(argv)
299 return super(TerminalIPythonApp, self).parse_command_line(argv)
295
300
296 @catch_config_error
301 @catch_config_error
297 def initialize(self, argv=None):
302 def initialize(self, argv=None):
298 """Do actions after construct, but before starting the app."""
303 """Do actions after construct, but before starting the app."""
299 super(TerminalIPythonApp, self).initialize(argv)
304 super(TerminalIPythonApp, self).initialize(argv)
300 if self.subapp is not None:
305 if self.subapp is not None:
301 # don't bother initializing further, starting subapp
306 # don't bother initializing further, starting subapp
302 return
307 return
303 # print self.extra_args
308 # print self.extra_args
304 if self.extra_args and not self.something_to_run:
309 if self.extra_args and not self.something_to_run:
305 self.file_to_run = self.extra_args[0]
310 self.file_to_run = self.extra_args[0]
306 self.init_path()
311 self.init_path()
307 # create the shell
312 # create the shell
308 self.init_shell()
313 self.init_shell()
309 # and draw the banner
314 # and draw the banner
310 self.init_banner()
315 self.init_banner()
311 # Now a variety of things that happen after the banner is printed.
316 # Now a variety of things that happen after the banner is printed.
312 self.init_gui_pylab()
317 self.init_gui_pylab()
313 self.init_extensions()
318 self.init_extensions()
314 self.init_code()
319 self.init_code()
315
320
316 def init_shell(self):
321 def init_shell(self):
317 """initialize the InteractiveShell instance"""
322 """initialize the InteractiveShell instance"""
318 # Create an InteractiveShell instance.
323 # Create an InteractiveShell instance.
319 # shell.display_banner should always be False for the terminal
324 # shell.display_banner should always be False for the terminal
320 # based app, because we call shell.show_banner() by hand below
325 # based app, because we call shell.show_banner() by hand below
321 # so the banner shows *before* all extension loading stuff.
326 # so the banner shows *before* all extension loading stuff.
322 self.shell = TerminalInteractiveShell.instance(parent=self,
327 self.shell = TerminalInteractiveShell.instance(parent=self,
323 profile_dir=self.profile_dir,
328 profile_dir=self.profile_dir,
324 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
329 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
325 self.shell.configurables.append(self)
330 self.shell.configurables.append(self)
326
331
327 def init_banner(self):
332 def init_banner(self):
328 """optionally display the banner"""
333 """optionally display the banner"""
329 if self.display_banner and self.interact:
334 if self.display_banner and self.interact:
330 self.shell.show_banner()
335 self.shell.show_banner()
331 # Make sure there is a space below the banner.
336 # Make sure there is a space below the banner.
332 if self.log_level <= logging.INFO: print()
337 if self.log_level <= logging.INFO: print()
333
338
334 def _pylab_changed(self, name, old, new):
339 def _pylab_changed(self, name, old, new):
335 """Replace --pylab='inline' with --pylab='auto'"""
340 """Replace --pylab='inline' with --pylab='auto'"""
336 if new == 'inline':
341 if new == 'inline':
337 warnings.warn("'inline' not available as pylab backend, "
342 warnings.warn("'inline' not available as pylab backend, "
338 "using 'auto' instead.")
343 "using 'auto' instead.")
339 self.pylab = 'auto'
344 self.pylab = 'auto'
340
345
341 def start(self):
346 def start(self):
342 if self.subapp is not None:
347 if self.subapp is not None:
343 return self.subapp.start()
348 return self.subapp.start()
344 # perform any prexec steps:
349 # perform any prexec steps:
345 if self.interact:
350 if self.interact:
346 self.log.debug("Starting IPython's mainloop...")
351 self.log.debug("Starting IPython's mainloop...")
347 self.shell.mainloop()
352 self.shell.mainloop()
348 else:
353 else:
349 self.log.debug("IPython not interactive...")
354 self.log.debug("IPython not interactive...")
350
355
351 def load_default_config(ipython_dir=None):
356 def load_default_config(ipython_dir=None):
352 """Load the default config file from the default ipython_dir.
357 """Load the default config file from the default ipython_dir.
353
358
354 This is useful for embedded shells.
359 This is useful for embedded shells.
355 """
360 """
356 if ipython_dir is None:
361 if ipython_dir is None:
357 ipython_dir = get_ipython_dir()
362 ipython_dir = get_ipython_dir()
358
363
359 profile_dir = os.path.join(ipython_dir, 'profile_default')
364 profile_dir = os.path.join(ipython_dir, 'profile_default')
360
365
361 config = Config()
366 config = Config()
362 for cf in Application._load_config_files("ipython_config", path=profile_dir):
367 for cf in Application._load_config_files("ipython_config", path=profile_dir):
363 config.update(cf)
368 config.update(cf)
364
369
365 return config
370 return config
366
371
367 launch_new_instance = TerminalIPythonApp.launch_instance
372 launch_new_instance = TerminalIPythonApp.launch_instance
368
373
369
374
370 if __name__ == '__main__':
375 if __name__ == '__main__':
371 launch_new_instance()
376 launch_new_instance()
@@ -1,428 +1,441 b''
1 """IPython terminal interface using prompt_toolkit in place of readline"""
1 """IPython terminal interface using prompt_toolkit in place of readline"""
2 from __future__ import print_function
2 from __future__ import print_function
3
3
4 import os
4 import os
5 import sys
5 import sys
6 import signal
6 import signal
7 from warnings import warn
7 from warnings import warn
8
8
9 from IPython.core.error import TryNext
9 from IPython.core.error import TryNext
10 from IPython.core.interactiveshell import InteractiveShell
10 from IPython.core.interactiveshell import InteractiveShell
11 from IPython.utils.py3compat import cast_unicode_py2, input
11 from IPython.utils.py3compat import cast_unicode_py2, input
12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
13 from IPython.utils.process import abbrev_cwd
13 from IPython.utils.process import abbrev_cwd
14 from traitlets import Bool, Unicode, Dict, Integer, observe
14 from traitlets import Bool, Unicode, Dict, Integer, observe
15
15
16 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
16 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
17 from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone
17 from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone
18 from prompt_toolkit.history import InMemoryHistory
18 from prompt_toolkit.history import InMemoryHistory
19 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout
19 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout
20 from prompt_toolkit.interface import CommandLineInterface
20 from prompt_toolkit.interface import CommandLineInterface
21 from prompt_toolkit.key_binding.manager import KeyBindingManager
21 from prompt_toolkit.key_binding.manager import KeyBindingManager
22 from prompt_toolkit.keys import Keys
22 from prompt_toolkit.keys import Keys
23 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
23 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
24 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
24 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
25
25
26 from pygments.styles import get_style_by_name, get_all_styles
26 from pygments.styles import get_style_by_name, get_all_styles
27 from pygments.token import Token
27 from pygments.token import Token
28
28
29 from .debugger import TerminalPdb
29 from .debugger import TerminalPdb
30 from .pt_inputhooks import get_inputhook_func
30 from .pt_inputhooks import get_inputhook_func
31 from .interactiveshell import get_default_editor, TerminalMagics
31 from .interactiveshell import get_default_editor, TerminalMagics
32 from .ptutils import IPythonPTCompleter, IPythonPTLexer
32 from .ptutils import IPythonPTCompleter, IPythonPTLexer
33
33
34 _use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty()
34
35
35 class TerminalInteractiveShell(InteractiveShell):
36 class TerminalInteractiveShell(InteractiveShell):
36 colors_force = True
37 colors_force = True
37
38
38 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
39 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
39 'to reserve for the completion menu'
40 'to reserve for the completion menu'
40 ).tag(config=True)
41 ).tag(config=True)
41
42
42 def _space_for_menu_changed(self, old, new):
43 def _space_for_menu_changed(self, old, new):
43 self._update_layout()
44 self._update_layout()
44
45
45 pt_cli = None
46 pt_cli = None
46 debugger_history = None
47 debugger_history = None
47 debugger_cls = TerminalPdb
48 debugger_cls = TerminalPdb
48
49
50 simple_prompt = Bool(_use_simple_prompt,
51 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
52
53 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
54 IPython own testing machinery, and emacs inferior-shell integration through elpy.
55
56 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
57 environment variable is set, or the current terminal is not a tty.
58
59 """
60 ).tag(config=True)
61
49 autoedit_syntax = Bool(False,
62 autoedit_syntax = Bool(False,
50 help="auto editing of files with syntax errors.",
63 help="auto editing of files with syntax errors.",
51 ).tag(config=True)
64 ).tag(config=True)
52
65
53
66
54 confirm_exit = Bool(True,
67 confirm_exit = Bool(True,
55 help="""
68 help="""
56 Set to confirm when you try to exit IPython with an EOF (Control-D
69 Set to confirm when you try to exit IPython with an EOF (Control-D
57 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
70 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
58 you can force a direct exit without any confirmation.""",
71 you can force a direct exit without any confirmation.""",
59 ).tag(config=True)
72 ).tag(config=True)
60
73
61 editing_mode = Unicode('emacs',
74 editing_mode = Unicode('emacs',
62 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
75 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
63 ).tag(config=True)
76 ).tag(config=True)
64
77
65 mouse_support = Bool(False,
78 mouse_support = Bool(False,
66 help="Enable mouse support in the prompt"
79 help="Enable mouse support in the prompt"
67 ).tag(config=True)
80 ).tag(config=True)
68
81
69 highlighting_style = Unicode('default',
82 highlighting_style = Unicode('default',
70 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
83 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
71 ).tag(config=True)
84 ).tag(config=True)
72
85
73
86
74 @observe('highlighting_style')
87 @observe('highlighting_style')
75 def _highlighting_style_changed(self, change):
88 def _highlighting_style_changed(self, change):
76 self._style = self._make_style_from_name(self.highlighting_style)
89 self._style = self._make_style_from_name(self.highlighting_style)
77
90
78 highlighting_style_overrides = Dict(
91 highlighting_style_overrides = Dict(
79 help="Override highlighting format for specific tokens"
92 help="Override highlighting format for specific tokens"
80 ).tag(config=True)
93 ).tag(config=True)
81
94
82 editor = Unicode(get_default_editor(),
95 editor = Unicode(get_default_editor(),
83 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
96 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
84 ).tag(config=True)
97 ).tag(config=True)
85
98
86 term_title = Bool(True,
99 term_title = Bool(True,
87 help="Automatically set the terminal title"
100 help="Automatically set the terminal title"
88 ).tag(config=True)
101 ).tag(config=True)
89
102
90 display_completions_in_columns = Bool(False,
103 display_completions_in_columns = Bool(False,
91 help="Display a multi column completion menu.",
104 help="Display a multi column completion menu.",
92 ).tag(config=True)
105 ).tag(config=True)
93
106
94 highlight_matching_brackets = Bool(True,
107 highlight_matching_brackets = Bool(True,
95 help="Highlight matching brackets .",
108 help="Highlight matching brackets .",
96 ).tag(config=True)
109 ).tag(config=True)
97
110
98 @observe('term_title')
111 @observe('term_title')
99 def init_term_title(self, change=None):
112 def init_term_title(self, change=None):
100 # Enable or disable the terminal title.
113 # Enable or disable the terminal title.
101 if self.term_title:
114 if self.term_title:
102 toggle_set_term_title(True)
115 toggle_set_term_title(True)
103 set_term_title('IPython: ' + abbrev_cwd())
116 set_term_title('IPython: ' + abbrev_cwd())
104 else:
117 else:
105 toggle_set_term_title(False)
118 toggle_set_term_title(False)
106
119
107 def get_prompt_tokens(self, cli):
120 def get_prompt_tokens(self, cli):
108 return [
121 return [
109 (Token.Prompt, 'In ['),
122 (Token.Prompt, 'In ['),
110 (Token.PromptNum, str(self.execution_count)),
123 (Token.PromptNum, str(self.execution_count)),
111 (Token.Prompt, ']: '),
124 (Token.Prompt, ']: '),
112 ]
125 ]
113
126
114 def get_continuation_tokens(self, cli, width):
127 def get_continuation_tokens(self, cli, width):
115 return [
128 return [
116 (Token.Prompt, (' ' * (width - 5)) + '...: '),
129 (Token.Prompt, (' ' * (width - 5)) + '...: '),
117 ]
130 ]
118
131
119 def init_prompt_toolkit_cli(self):
132 def init_prompt_toolkit_cli(self):
120 if ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or not sys.stdin.isatty():
133 if self.simple_prompt:
121 # Fall back to plain non-interactive output for tests.
134 # Fall back to plain non-interactive output for tests.
122 # This is very limited, and only accepts a single line.
135 # This is very limited, and only accepts a single line.
123 def prompt():
136 def prompt():
124 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
137 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
125 self.prompt_for_code = prompt
138 self.prompt_for_code = prompt
126 return
139 return
127
140
128 kbmanager = KeyBindingManager.for_prompt()
141 kbmanager = KeyBindingManager.for_prompt()
129 insert_mode = ViInsertMode() | EmacsInsertMode()
142 insert_mode = ViInsertMode() | EmacsInsertMode()
130 # Ctrl+J == Enter, seemingly
143 # Ctrl+J == Enter, seemingly
131 @kbmanager.registry.add_binding(Keys.ControlJ,
144 @kbmanager.registry.add_binding(Keys.ControlJ,
132 filter=(HasFocus(DEFAULT_BUFFER)
145 filter=(HasFocus(DEFAULT_BUFFER)
133 & ~HasSelection()
146 & ~HasSelection()
134 & insert_mode
147 & insert_mode
135 ))
148 ))
136 def _(event):
149 def _(event):
137 b = event.current_buffer
150 b = event.current_buffer
138 d = b.document
151 d = b.document
139 if not (d.on_last_line or d.cursor_position_row >= d.line_count
152 if not (d.on_last_line or d.cursor_position_row >= d.line_count
140 - d.empty_line_count_at_the_end()):
153 - d.empty_line_count_at_the_end()):
141 b.newline()
154 b.newline()
142 return
155 return
143
156
144 status, indent = self.input_splitter.check_complete(d.text)
157 status, indent = self.input_splitter.check_complete(d.text)
145
158
146 if (status != 'incomplete') and b.accept_action.is_returnable:
159 if (status != 'incomplete') and b.accept_action.is_returnable:
147 b.accept_action.validate_and_handle(event.cli, b)
160 b.accept_action.validate_and_handle(event.cli, b)
148 else:
161 else:
149 b.insert_text('\n' + (' ' * (indent or 0)))
162 b.insert_text('\n' + (' ' * (indent or 0)))
150
163
151 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER))
164 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER))
152 def _reset_buffer(event):
165 def _reset_buffer(event):
153 event.current_buffer.reset()
166 event.current_buffer.reset()
154
167
155 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER))
168 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER))
156 def _reset_search_buffer(event):
169 def _reset_search_buffer(event):
157 if event.current_buffer.document.text:
170 if event.current_buffer.document.text:
158 event.current_buffer.reset()
171 event.current_buffer.reset()
159 else:
172 else:
160 event.cli.push_focus(DEFAULT_BUFFER)
173 event.cli.push_focus(DEFAULT_BUFFER)
161
174
162 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
175 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
163
176
164 @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
177 @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
165 def _suspend_to_bg(event):
178 def _suspend_to_bg(event):
166 event.cli.suspend_to_background()
179 event.cli.suspend_to_background()
167
180
168 @Condition
181 @Condition
169 def cursor_in_leading_ws(cli):
182 def cursor_in_leading_ws(cli):
170 before = cli.application.buffer.document.current_line_before_cursor
183 before = cli.application.buffer.document.current_line_before_cursor
171 return (not before) or before.isspace()
184 return (not before) or before.isspace()
172
185
173 # Ctrl+I == Tab
186 # Ctrl+I == Tab
174 @kbmanager.registry.add_binding(Keys.ControlI,
187 @kbmanager.registry.add_binding(Keys.ControlI,
175 filter=(HasFocus(DEFAULT_BUFFER)
188 filter=(HasFocus(DEFAULT_BUFFER)
176 & ~HasSelection()
189 & ~HasSelection()
177 & insert_mode
190 & insert_mode
178 & cursor_in_leading_ws
191 & cursor_in_leading_ws
179 ))
192 ))
180 def _indent_buffer(event):
193 def _indent_buffer(event):
181 event.current_buffer.insert_text(' ' * 4)
194 event.current_buffer.insert_text(' ' * 4)
182
195
183 # Pre-populate history from IPython's history database
196 # Pre-populate history from IPython's history database
184 history = InMemoryHistory()
197 history = InMemoryHistory()
185 last_cell = u""
198 last_cell = u""
186 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
199 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
187 include_latest=True):
200 include_latest=True):
188 # Ignore blank lines and consecutive duplicates
201 # Ignore blank lines and consecutive duplicates
189 cell = cell.rstrip()
202 cell = cell.rstrip()
190 if cell and (cell != last_cell):
203 if cell and (cell != last_cell):
191 history.append(cell)
204 history.append(cell)
192
205
193 self._style = self._make_style_from_name(self.highlighting_style)
206 self._style = self._make_style_from_name(self.highlighting_style)
194 style = DynamicStyle(lambda: self._style)
207 style = DynamicStyle(lambda: self._style)
195
208
196 editing_mode = getattr(EditingMode, self.editing_mode.upper())
209 editing_mode = getattr(EditingMode, self.editing_mode.upper())
197
210
198 self._app = create_prompt_application(
211 self._app = create_prompt_application(
199 editing_mode=editing_mode,
212 editing_mode=editing_mode,
200 key_bindings_registry=kbmanager.registry,
213 key_bindings_registry=kbmanager.registry,
201 history=history,
214 history=history,
202 completer=IPythonPTCompleter(self.Completer),
215 completer=IPythonPTCompleter(self.Completer),
203 enable_history_search=True,
216 enable_history_search=True,
204 style=style,
217 style=style,
205 mouse_support=self.mouse_support,
218 mouse_support=self.mouse_support,
206 **self._layout_options()
219 **self._layout_options()
207 )
220 )
208 self._eventloop = create_eventloop(self.inputhook)
221 self._eventloop = create_eventloop(self.inputhook)
209 self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop)
222 self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop)
210
223
211 def _make_style_from_name(self, name):
224 def _make_style_from_name(self, name):
212 """
225 """
213 Small wrapper that make an IPython compatible style from a style name
226 Small wrapper that make an IPython compatible style from a style name
214
227
215 We need that to add style for prompt ... etc.
228 We need that to add style for prompt ... etc.
216 """
229 """
217 style_cls = get_style_by_name(name)
230 style_cls = get_style_by_name(name)
218 style_overrides = {
231 style_overrides = {
219 Token.Prompt: '#009900',
232 Token.Prompt: '#009900',
220 Token.PromptNum: '#00ff00 bold',
233 Token.PromptNum: '#00ff00 bold',
221 }
234 }
222 if name == 'default':
235 if name == 'default':
223 style_cls = get_style_by_name('default')
236 style_cls = get_style_by_name('default')
224 # The default theme needs to be visible on both a dark background
237 # The default theme needs to be visible on both a dark background
225 # and a light background, because we can't tell what the terminal
238 # and a light background, because we can't tell what the terminal
226 # looks like. These tweaks to the default theme help with that.
239 # looks like. These tweaks to the default theme help with that.
227 style_overrides.update({
240 style_overrides.update({
228 Token.Number: '#007700',
241 Token.Number: '#007700',
229 Token.Operator: 'noinherit',
242 Token.Operator: 'noinherit',
230 Token.String: '#BB6622',
243 Token.String: '#BB6622',
231 Token.Name.Function: '#2080D0',
244 Token.Name.Function: '#2080D0',
232 Token.Name.Class: 'bold #2080D0',
245 Token.Name.Class: 'bold #2080D0',
233 Token.Name.Namespace: 'bold #2080D0',
246 Token.Name.Namespace: 'bold #2080D0',
234 })
247 })
235 style_overrides.update(self.highlighting_style_overrides)
248 style_overrides.update(self.highlighting_style_overrides)
236 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
249 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
237 style_dict=style_overrides)
250 style_dict=style_overrides)
238
251
239 return style
252 return style
240
253
241 def _layout_options(self):
254 def _layout_options(self):
242 """
255 """
243 Return the current layout option for the current Terminal InteractiveShell
256 Return the current layout option for the current Terminal InteractiveShell
244 """
257 """
245 return {
258 return {
246 'lexer':IPythonPTLexer(),
259 'lexer':IPythonPTLexer(),
247 'reserve_space_for_menu':self.space_for_menu,
260 'reserve_space_for_menu':self.space_for_menu,
248 'get_prompt_tokens':self.get_prompt_tokens,
261 'get_prompt_tokens':self.get_prompt_tokens,
249 'get_continuation_tokens':self.get_continuation_tokens,
262 'get_continuation_tokens':self.get_continuation_tokens,
250 'multiline':True,
263 'multiline':True,
251 'display_completions_in_columns': self.display_completions_in_columns,
264 'display_completions_in_columns': self.display_completions_in_columns,
252
265
253 # Highlight matching brackets, but only when this setting is
266 # Highlight matching brackets, but only when this setting is
254 # enabled, and only when the DEFAULT_BUFFER has the focus.
267 # enabled, and only when the DEFAULT_BUFFER has the focus.
255 'extra_input_processors': [ConditionalProcessor(
268 'extra_input_processors': [ConditionalProcessor(
256 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
269 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
257 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
270 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
258 Condition(lambda cli: self.highlight_matching_brackets))],
271 Condition(lambda cli: self.highlight_matching_brackets))],
259 }
272 }
260
273
261 def _update_layout(self):
274 def _update_layout(self):
262 """
275 """
263 Ask for a re computation of the application layout, if for example ,
276 Ask for a re computation of the application layout, if for example ,
264 some configuration options have changed.
277 some configuration options have changed.
265 """
278 """
266 self._app.layout = create_prompt_layout(**self._layout_options())
279 self._app.layout = create_prompt_layout(**self._layout_options())
267
280
268 def prompt_for_code(self):
281 def prompt_for_code(self):
269 document = self.pt_cli.run(
282 document = self.pt_cli.run(
270 pre_run=self.pre_prompt, reset_current_buffer=True)
283 pre_run=self.pre_prompt, reset_current_buffer=True)
271 return document.text
284 return document.text
272
285
273 def init_io(self):
286 def init_io(self):
274 if sys.platform not in {'win32', 'cli'}:
287 if sys.platform not in {'win32', 'cli'}:
275 return
288 return
276
289
277 import colorama
290 import colorama
278 colorama.init()
291 colorama.init()
279
292
280 # For some reason we make these wrappers around stdout/stderr.
293 # For some reason we make these wrappers around stdout/stderr.
281 # For now, we need to reset them so all output gets coloured.
294 # For now, we need to reset them so all output gets coloured.
282 # https://github.com/ipython/ipython/issues/8669
295 # https://github.com/ipython/ipython/issues/8669
283 from IPython.utils import io
296 from IPython.utils import io
284 io.stdout = io.IOStream(sys.stdout)
297 io.stdout = io.IOStream(sys.stdout)
285 io.stderr = io.IOStream(sys.stderr)
298 io.stderr = io.IOStream(sys.stderr)
286
299
287 def init_magics(self):
300 def init_magics(self):
288 super(TerminalInteractiveShell, self).init_magics()
301 super(TerminalInteractiveShell, self).init_magics()
289 self.register_magics(TerminalMagics)
302 self.register_magics(TerminalMagics)
290
303
291 def init_alias(self):
304 def init_alias(self):
292 # The parent class defines aliases that can be safely used with any
305 # The parent class defines aliases that can be safely used with any
293 # frontend.
306 # frontend.
294 super(TerminalInteractiveShell, self).init_alias()
307 super(TerminalInteractiveShell, self).init_alias()
295
308
296 # Now define aliases that only make sense on the terminal, because they
309 # Now define aliases that only make sense on the terminal, because they
297 # need direct access to the console in a way that we can't emulate in
310 # need direct access to the console in a way that we can't emulate in
298 # GUI or web frontend
311 # GUI or web frontend
299 if os.name == 'posix':
312 if os.name == 'posix':
300 for cmd in ['clear', 'more', 'less', 'man']:
313 for cmd in ['clear', 'more', 'less', 'man']:
301 self.alias_manager.soft_define_alias(cmd, cmd)
314 self.alias_manager.soft_define_alias(cmd, cmd)
302
315
303
316
304 def __init__(self, *args, **kwargs):
317 def __init__(self, *args, **kwargs):
305 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
318 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
306 self.init_prompt_toolkit_cli()
319 self.init_prompt_toolkit_cli()
307 self.init_term_title()
320 self.init_term_title()
308 self.keep_running = True
321 self.keep_running = True
309
322
310 self.debugger_history = InMemoryHistory()
323 self.debugger_history = InMemoryHistory()
311
324
312 def ask_exit(self):
325 def ask_exit(self):
313 self.keep_running = False
326 self.keep_running = False
314
327
315 rl_next_input = None
328 rl_next_input = None
316
329
317 def pre_prompt(self):
330 def pre_prompt(self):
318 if self.rl_next_input:
331 if self.rl_next_input:
319 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
332 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
320 self.rl_next_input = None
333 self.rl_next_input = None
321
334
322 def interact(self):
335 def interact(self):
323 while self.keep_running:
336 while self.keep_running:
324 print(self.separate_in, end='')
337 print(self.separate_in, end='')
325
338
326 try:
339 try:
327 code = self.prompt_for_code()
340 code = self.prompt_for_code()
328 except EOFError:
341 except EOFError:
329 if (not self.confirm_exit) \
342 if (not self.confirm_exit) \
330 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
343 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
331 self.ask_exit()
344 self.ask_exit()
332
345
333 else:
346 else:
334 if code:
347 if code:
335 self.run_cell(code, store_history=True)
348 self.run_cell(code, store_history=True)
336 if self.autoedit_syntax and self.SyntaxTB.last_syntax_error:
349 if self.autoedit_syntax and self.SyntaxTB.last_syntax_error:
337 self.edit_syntax_error()
350 self.edit_syntax_error()
338
351
339 def mainloop(self):
352 def mainloop(self):
340 # An extra layer of protection in case someone mashing Ctrl-C breaks
353 # An extra layer of protection in case someone mashing Ctrl-C breaks
341 # out of our internal code.
354 # out of our internal code.
342 while True:
355 while True:
343 try:
356 try:
344 self.interact()
357 self.interact()
345 break
358 break
346 except KeyboardInterrupt:
359 except KeyboardInterrupt:
347 print("\nKeyboardInterrupt escaped interact()\n")
360 print("\nKeyboardInterrupt escaped interact()\n")
348
361
349 if hasattr(self, '_eventloop'):
362 if hasattr(self, '_eventloop'):
350 self._eventloop.close()
363 self._eventloop.close()
351
364
352 _inputhook = None
365 _inputhook = None
353 def inputhook(self, context):
366 def inputhook(self, context):
354 if self._inputhook is not None:
367 if self._inputhook is not None:
355 self._inputhook(context)
368 self._inputhook(context)
356
369
357 def enable_gui(self, gui=None):
370 def enable_gui(self, gui=None):
358 if gui:
371 if gui:
359 self._inputhook = get_inputhook_func(gui)
372 self._inputhook = get_inputhook_func(gui)
360 else:
373 else:
361 self._inputhook = None
374 self._inputhook = None
362
375
363 # Methods to support auto-editing of SyntaxErrors:
376 # Methods to support auto-editing of SyntaxErrors:
364
377
365 def edit_syntax_error(self):
378 def edit_syntax_error(self):
366 """The bottom half of the syntax error handler called in the main loop.
379 """The bottom half of the syntax error handler called in the main loop.
367
380
368 Loop until syntax error is fixed or user cancels.
381 Loop until syntax error is fixed or user cancels.
369 """
382 """
370
383
371 while self.SyntaxTB.last_syntax_error:
384 while self.SyntaxTB.last_syntax_error:
372 # copy and clear last_syntax_error
385 # copy and clear last_syntax_error
373 err = self.SyntaxTB.clear_err_state()
386 err = self.SyntaxTB.clear_err_state()
374 if not self._should_recompile(err):
387 if not self._should_recompile(err):
375 return
388 return
376 try:
389 try:
377 # may set last_syntax_error again if a SyntaxError is raised
390 # may set last_syntax_error again if a SyntaxError is raised
378 self.safe_execfile(err.filename, self.user_ns)
391 self.safe_execfile(err.filename, self.user_ns)
379 except:
392 except:
380 self.showtraceback()
393 self.showtraceback()
381 else:
394 else:
382 try:
395 try:
383 with open(err.filename) as f:
396 with open(err.filename) as f:
384 # This should be inside a display_trap block and I
397 # This should be inside a display_trap block and I
385 # think it is.
398 # think it is.
386 sys.displayhook(f.read())
399 sys.displayhook(f.read())
387 except:
400 except:
388 self.showtraceback()
401 self.showtraceback()
389
402
390 def _should_recompile(self, e):
403 def _should_recompile(self, e):
391 """Utility routine for edit_syntax_error"""
404 """Utility routine for edit_syntax_error"""
392
405
393 if e.filename in ('<ipython console>', '<input>', '<string>',
406 if e.filename in ('<ipython console>', '<input>', '<string>',
394 '<console>', '<BackgroundJob compilation>',
407 '<console>', '<BackgroundJob compilation>',
395 None):
408 None):
396 return False
409 return False
397 try:
410 try:
398 if (self.autoedit_syntax and
411 if (self.autoedit_syntax and
399 not self.ask_yes_no(
412 not self.ask_yes_no(
400 'Return to editor to correct syntax error? '
413 'Return to editor to correct syntax error? '
401 '[Y/n] ', 'y')):
414 '[Y/n] ', 'y')):
402 return False
415 return False
403 except EOFError:
416 except EOFError:
404 return False
417 return False
405
418
406 def int0(x):
419 def int0(x):
407 try:
420 try:
408 return int(x)
421 return int(x)
409 except TypeError:
422 except TypeError:
410 return 0
423 return 0
411
424
412 # always pass integer line and offset values to editor hook
425 # always pass integer line and offset values to editor hook
413 try:
426 try:
414 self.hooks.fix_error_editor(e.filename,
427 self.hooks.fix_error_editor(e.filename,
415 int0(e.lineno), int0(e.offset),
428 int0(e.lineno), int0(e.offset),
416 e.msg)
429 e.msg)
417 except TryNext:
430 except TryNext:
418 warn('Could not open editor')
431 warn('Could not open editor')
419 return False
432 return False
420 return True
433 return True
421
434
422 # Run !system commands directly, not through pipes, so terminal programs
435 # Run !system commands directly, not through pipes, so terminal programs
423 # work correctly.
436 # work correctly.
424 system = InteractiveShell.system_raw
437 system = InteractiveShell.system_raw
425
438
426
439
427 if __name__ == '__main__':
440 if __name__ == '__main__':
428 TerminalInteractiveShell.instance().interact()
441 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now