##// END OF EJS Templates
Fixed formatting at end of lines
michaelpacer -
Show More
@@ -1,457 +1,457
1 """IPython terminal interface using prompt_toolkit"""
1 """IPython terminal interface using prompt_toolkit"""
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 from warnings import warn
6 from warnings import warn
7
7
8 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
8 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
9 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
9 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
10 from IPython.utils.terminal import toggle_set_term_title, set_term_title
10 from IPython.utils.terminal import toggle_set_term_title, set_term_title
11 from IPython.utils.process import abbrev_cwd
11 from IPython.utils.process import abbrev_cwd
12 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum
12 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum
13
13
14 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
14 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
15 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
15 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
16 from prompt_toolkit.history import InMemoryHistory
16 from prompt_toolkit.history import InMemoryHistory
17 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output
17 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output
18 from prompt_toolkit.interface import CommandLineInterface
18 from prompt_toolkit.interface import CommandLineInterface
19 from prompt_toolkit.key_binding.manager import KeyBindingManager
19 from prompt_toolkit.key_binding.manager import KeyBindingManager
20 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
20 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
21 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
21 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
22
22
23 from pygments.styles import get_style_by_name, get_all_styles
23 from pygments.styles import get_style_by_name, get_all_styles
24 from pygments.token import Token
24 from pygments.token import Token
25
25
26 from .debugger import TerminalPdb, Pdb
26 from .debugger import TerminalPdb, Pdb
27 from .magics import TerminalMagics
27 from .magics import TerminalMagics
28 from .pt_inputhooks import get_inputhook_func
28 from .pt_inputhooks import get_inputhook_func
29 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
29 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
30 from .ptutils import IPythonPTCompleter, IPythonPTLexer
30 from .ptutils import IPythonPTCompleter, IPythonPTLexer
31 from .shortcuts import register_ipython_shortcuts
31 from .shortcuts import register_ipython_shortcuts
32
32
33 DISPLAY_BANNER_DEPRECATED = object()
33 DISPLAY_BANNER_DEPRECATED = object()
34
34
35
35
36 from pygments.style import Style
36 from pygments.style import Style
37
37
38 class _NoStyle(Style): pass
38 class _NoStyle(Style): pass
39
39
40
40
41
41
42 _style_overrides_light_bg = {
42 _style_overrides_light_bg = {
43 Token.Prompt: '#0000ff',
43 Token.Prompt: '#0000ff',
44 Token.PromptNum: '#0000ee bold',
44 Token.PromptNum: '#0000ee bold',
45 Token.OutPrompt: '#cc0000',
45 Token.OutPrompt: '#cc0000',
46 Token.OutPromptNum: '#bb0000 bold',
46 Token.OutPromptNum: '#bb0000 bold',
47 }
47 }
48
48
49 _style_overrides_linux = {
49 _style_overrides_linux = {
50 Token.Prompt: '#00cc00',
50 Token.Prompt: '#00cc00',
51 Token.PromptNum: '#00bb00 bold',
51 Token.PromptNum: '#00bb00 bold',
52 Token.OutPrompt: '#cc0000',
52 Token.OutPrompt: '#cc0000',
53 Token.OutPromptNum: '#bb0000 bold',
53 Token.OutPromptNum: '#bb0000 bold',
54 }
54 }
55
55
56
56
57
57
58 def get_default_editor():
58 def get_default_editor():
59 try:
59 try:
60 ed = os.environ['EDITOR']
60 ed = os.environ['EDITOR']
61 if not PY3:
61 if not PY3:
62 ed = ed.decode()
62 ed = ed.decode()
63 return ed
63 return ed
64 except KeyError:
64 except KeyError:
65 pass
65 pass
66 except UnicodeError:
66 except UnicodeError:
67 warn("$EDITOR environment variable is not pure ASCII. Using platform "
67 warn("$EDITOR environment variable is not pure ASCII. Using platform "
68 "default editor.")
68 "default editor.")
69
69
70 if os.name == 'posix':
70 if os.name == 'posix':
71 return 'vi' # the only one guaranteed to be there!
71 return 'vi' # the only one guaranteed to be there!
72 else:
72 else:
73 return 'notepad' # same in Windows!
73 return 'notepad' # same in Windows!
74
74
75
75
76 if sys.stdin and sys.stdout and sys.stderr:
76 if sys.stdin and sys.stdout and sys.stderr:
77 _is_tty = (sys.stdin.isatty()) and (sys.stdout.isatty()) and (sys.stderr.isatty())
77 _is_tty = (sys.stdin.isatty()) and (sys.stdout.isatty()) and (sys.stderr.isatty())
78 else:
78 else:
79 _is_tty = False
79 _is_tty = False
80
80
81
81
82 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
82 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
83
83
84 class TerminalInteractiveShell(InteractiveShell):
84 class TerminalInteractiveShell(InteractiveShell):
85 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
85 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
86 'to reserve for the completion menu'
86 'to reserve for the completion menu'
87 ).tag(config=True)
87 ).tag(config=True)
88
88
89 def _space_for_menu_changed(self, old, new):
89 def _space_for_menu_changed(self, old, new):
90 self._update_layout()
90 self._update_layout()
91
91
92 pt_cli = None
92 pt_cli = None
93 debugger_history = None
93 debugger_history = None
94 _pt_app = None
94 _pt_app = None
95
95
96 simple_prompt = Bool(_use_simple_prompt,
96 simple_prompt = Bool(_use_simple_prompt,
97 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
97 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
98
98
99 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
99 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
100 IPython own testing machinery, and emacs inferior-shell integration through elpy.
100 IPython own testing machinery, and emacs inferior-shell integration through elpy.
101
101
102 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
102 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
103 environment variable is set, or the current terminal is not a tty.
103 environment variable is set, or the current terminal is not a tty.
104
104
105 """
105 """
106 ).tag(config=True)
106 ).tag(config=True)
107
107
108 @property
108 @property
109 def debugger_cls(self):
109 def debugger_cls(self):
110 return Pdb if self.simple_prompt else TerminalPdb
110 return Pdb if self.simple_prompt else TerminalPdb
111
111
112 confirm_exit = Bool(True,
112 confirm_exit = Bool(True,
113 help="""
113 help="""
114 Set to confirm when you try to exit IPython with an EOF (Control-D
114 Set to confirm when you try to exit IPython with an EOF (Control-D
115 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
115 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
116 you can force a direct exit without any confirmation.""",
116 you can force a direct exit without any confirmation.""",
117 ).tag(config=True)
117 ).tag(config=True)
118
118
119 editing_mode = Unicode('emacs',
119 editing_mode = Unicode('emacs',
120 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
120 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
121 ).tag(config=True)
121 ).tag(config=True)
122
122
123 mouse_support = Bool(False,
123 mouse_support = Bool(False,
124 help="Enable mouse support in the prompt"
124 help="Enable mouse support in the prompt"
125 ).tag(config=True)
125 ).tag(config=True)
126
126
127 highlighting_style = Unicode('legacy',
127 highlighting_style = Unicode('legacy',
128 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
128 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
129 ).tag(config=True)
129 ).tag(config=True)
130
130
131
131
132 @observe('highlighting_style')
132 @observe('highlighting_style')
133 @observe('colors')
133 @observe('colors')
134 def _highlighting_style_changed(self, change):
134 def _highlighting_style_changed(self, change):
135 self.refresh_style()
135 self.refresh_style()
136
136
137 def refresh_style(self):
137 def refresh_style(self):
138 self._style = self._make_style_from_name(self.highlighting_style)
138 self._style = self._make_style_from_name(self.highlighting_style)
139
139
140
140
141 highlighting_style_overrides = Dict(
141 highlighting_style_overrides = Dict(
142 help="Override highlighting format for specific tokens"
142 help="Override highlighting format for specific tokens"
143 ).tag(config=True)
143 ).tag(config=True)
144
144
145 true_color = Bool(False,
145 true_color = Bool(False,
146 help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
146 help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
147 "If your terminal supports true color, the following command "
147 "If your terminal supports true color, the following command "
148 "should print 'TRUECOLOR' in orange: "
148 "should print 'TRUECOLOR' in orange: "
149 "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
149 "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
150 ).tag(config=True)
150 ).tag(config=True)
151
151
152 editor = Unicode(get_default_editor(),
152 editor = Unicode(get_default_editor(),
153 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
153 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
154 ).tag(config=True)
154 ).tag(config=True)
155
155
156 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
156 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
157
157
158 prompts = Instance(Prompts)
158 prompts = Instance(Prompts)
159
159
160 @default('prompts')
160 @default('prompts')
161 def _prompts_default(self):
161 def _prompts_default(self):
162 return self.prompts_class(self)
162 return self.prompts_class(self)
163
163
164 @observe('prompts')
164 @observe('prompts')
165 def _(self, change):
165 def _(self, change):
166 self._update_layout()
166 self._update_layout()
167
167
168 @default('displayhook_class')
168 @default('displayhook_class')
169 def _displayhook_class_default(self):
169 def _displayhook_class_default(self):
170 return RichPromptDisplayHook
170 return RichPromptDisplayHook
171
171
172 term_title = Bool(True,
172 term_title = Bool(True,
173 help="Automatically set the terminal title"
173 help="Automatically set the terminal title"
174 ).tag(config=True)
174 ).tag(config=True)
175
175
176 display_completions = Enum(('column', 'multicolumn','readlinelike'),
176 display_completions = Enum(('column', 'multicolumn','readlinelike'),
177 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and"
177 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
178 "'readlinelike'. These options are for `prompt_toolkit`, see `prompt_toolkit`"
178 "'readlinelike'. These options are for `prompt_toolkit`, see "
179 "documentation for more information."
179 "`prompt_toolkit` documentation for more information."
180 ),
180 ),
181 default_value='multicolumn').tag(config=True)
181 default_value='multicolumn').tag(config=True)
182
182
183 highlight_matching_brackets = Bool(True,
183 highlight_matching_brackets = Bool(True,
184 help="Highlight matching brackets .",
184 help="Highlight matching brackets .",
185 ).tag(config=True)
185 ).tag(config=True)
186
186
187 @observe('term_title')
187 @observe('term_title')
188 def init_term_title(self, change=None):
188 def init_term_title(self, change=None):
189 # Enable or disable the terminal title.
189 # Enable or disable the terminal title.
190 if self.term_title:
190 if self.term_title:
191 toggle_set_term_title(True)
191 toggle_set_term_title(True)
192 set_term_title('IPython: ' + abbrev_cwd())
192 set_term_title('IPython: ' + abbrev_cwd())
193 else:
193 else:
194 toggle_set_term_title(False)
194 toggle_set_term_title(False)
195
195
196 def init_display_formatter(self):
196 def init_display_formatter(self):
197 super(TerminalInteractiveShell, self).init_display_formatter()
197 super(TerminalInteractiveShell, self).init_display_formatter()
198 # terminal only supports plain text
198 # terminal only supports plain text
199 self.display_formatter.active_types = ['text/plain']
199 self.display_formatter.active_types = ['text/plain']
200
200
201 def init_prompt_toolkit_cli(self):
201 def init_prompt_toolkit_cli(self):
202 if self.simple_prompt:
202 if self.simple_prompt:
203 # Fall back to plain non-interactive output for tests.
203 # Fall back to plain non-interactive output for tests.
204 # This is very limited, and only accepts a single line.
204 # This is very limited, and only accepts a single line.
205 def prompt():
205 def prompt():
206 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
206 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
207 self.prompt_for_code = prompt
207 self.prompt_for_code = prompt
208 return
208 return
209
209
210 # Set up keyboard shortcuts
210 # Set up keyboard shortcuts
211 kbmanager = KeyBindingManager.for_prompt()
211 kbmanager = KeyBindingManager.for_prompt()
212 register_ipython_shortcuts(kbmanager.registry, self)
212 register_ipython_shortcuts(kbmanager.registry, self)
213
213
214 # Pre-populate history from IPython's history database
214 # Pre-populate history from IPython's history database
215 history = InMemoryHistory()
215 history = InMemoryHistory()
216 last_cell = u""
216 last_cell = u""
217 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
217 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
218 include_latest=True):
218 include_latest=True):
219 # Ignore blank lines and consecutive duplicates
219 # Ignore blank lines and consecutive duplicates
220 cell = cell.rstrip()
220 cell = cell.rstrip()
221 if cell and (cell != last_cell):
221 if cell and (cell != last_cell):
222 history.append(cell)
222 history.append(cell)
223
223
224 self._style = self._make_style_from_name(self.highlighting_style)
224 self._style = self._make_style_from_name(self.highlighting_style)
225 style = DynamicStyle(lambda: self._style)
225 style = DynamicStyle(lambda: self._style)
226
226
227 editing_mode = getattr(EditingMode, self.editing_mode.upper())
227 editing_mode = getattr(EditingMode, self.editing_mode.upper())
228
228
229 self._pt_app = create_prompt_application(
229 self._pt_app = create_prompt_application(
230 editing_mode=editing_mode,
230 editing_mode=editing_mode,
231 key_bindings_registry=kbmanager.registry,
231 key_bindings_registry=kbmanager.registry,
232 history=history,
232 history=history,
233 completer=IPythonPTCompleter(self.Completer),
233 completer=IPythonPTCompleter(self.Completer),
234 enable_history_search=True,
234 enable_history_search=True,
235 style=style,
235 style=style,
236 mouse_support=self.mouse_support,
236 mouse_support=self.mouse_support,
237 **self._layout_options()
237 **self._layout_options()
238 )
238 )
239 self._eventloop = create_eventloop(self.inputhook)
239 self._eventloop = create_eventloop(self.inputhook)
240 self.pt_cli = CommandLineInterface(
240 self.pt_cli = CommandLineInterface(
241 self._pt_app, eventloop=self._eventloop,
241 self._pt_app, eventloop=self._eventloop,
242 output=create_output(true_color=self.true_color))
242 output=create_output(true_color=self.true_color))
243
243
244 def _make_style_from_name(self, name):
244 def _make_style_from_name(self, name):
245 """
245 """
246 Small wrapper that make an IPython compatible style from a style name
246 Small wrapper that make an IPython compatible style from a style name
247
247
248 We need that to add style for prompt ... etc.
248 We need that to add style for prompt ... etc.
249 """
249 """
250 style_overrides = {}
250 style_overrides = {}
251 if name == 'legacy':
251 if name == 'legacy':
252 legacy = self.colors.lower()
252 legacy = self.colors.lower()
253 if legacy == 'linux':
253 if legacy == 'linux':
254 style_cls = get_style_by_name('monokai')
254 style_cls = get_style_by_name('monokai')
255 style_overrides = _style_overrides_linux
255 style_overrides = _style_overrides_linux
256 elif legacy == 'lightbg':
256 elif legacy == 'lightbg':
257 style_overrides = _style_overrides_light_bg
257 style_overrides = _style_overrides_light_bg
258 style_cls = get_style_by_name('pastie')
258 style_cls = get_style_by_name('pastie')
259 elif legacy == 'neutral':
259 elif legacy == 'neutral':
260 # The default theme needs to be visible on both a dark background
260 # The default theme needs to be visible on both a dark background
261 # and a light background, because we can't tell what the terminal
261 # and a light background, because we can't tell what the terminal
262 # looks like. These tweaks to the default theme help with that.
262 # looks like. These tweaks to the default theme help with that.
263 style_cls = get_style_by_name('default')
263 style_cls = get_style_by_name('default')
264 style_overrides.update({
264 style_overrides.update({
265 Token.Number: '#007700',
265 Token.Number: '#007700',
266 Token.Operator: 'noinherit',
266 Token.Operator: 'noinherit',
267 Token.String: '#BB6622',
267 Token.String: '#BB6622',
268 Token.Name.Function: '#2080D0',
268 Token.Name.Function: '#2080D0',
269 Token.Name.Class: 'bold #2080D0',
269 Token.Name.Class: 'bold #2080D0',
270 Token.Name.Namespace: 'bold #2080D0',
270 Token.Name.Namespace: 'bold #2080D0',
271 Token.Prompt: '#009900',
271 Token.Prompt: '#009900',
272 Token.PromptNum: '#00ff00 bold',
272 Token.PromptNum: '#00ff00 bold',
273 Token.OutPrompt: '#990000',
273 Token.OutPrompt: '#990000',
274 Token.OutPromptNum: '#ff0000 bold',
274 Token.OutPromptNum: '#ff0000 bold',
275 })
275 })
276 elif legacy =='nocolor':
276 elif legacy =='nocolor':
277 style_cls=_NoStyle
277 style_cls=_NoStyle
278 style_overrides = {}
278 style_overrides = {}
279 else :
279 else :
280 raise ValueError('Got unknown colors: ', legacy)
280 raise ValueError('Got unknown colors: ', legacy)
281 else :
281 else :
282 style_cls = get_style_by_name(name)
282 style_cls = get_style_by_name(name)
283 style_overrides = {
283 style_overrides = {
284 Token.Prompt: '#009900',
284 Token.Prompt: '#009900',
285 Token.PromptNum: '#00ff00 bold',
285 Token.PromptNum: '#00ff00 bold',
286 Token.OutPrompt: '#990000',
286 Token.OutPrompt: '#990000',
287 Token.OutPromptNum: '#ff0000 bold',
287 Token.OutPromptNum: '#ff0000 bold',
288 }
288 }
289 style_overrides.update(self.highlighting_style_overrides)
289 style_overrides.update(self.highlighting_style_overrides)
290 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
290 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
291 style_dict=style_overrides)
291 style_dict=style_overrides)
292
292
293 return style
293 return style
294
294
295 def _layout_options(self):
295 def _layout_options(self):
296 """
296 """
297 Return the current layout option for the current Terminal InteractiveShell
297 Return the current layout option for the current Terminal InteractiveShell
298 """
298 """
299 return {
299 return {
300 'lexer':IPythonPTLexer(),
300 'lexer':IPythonPTLexer(),
301 'reserve_space_for_menu':self.space_for_menu,
301 'reserve_space_for_menu':self.space_for_menu,
302 'get_prompt_tokens':self.prompts.in_prompt_tokens,
302 'get_prompt_tokens':self.prompts.in_prompt_tokens,
303 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
303 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
304 'multiline':True,
304 'multiline':True,
305 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
305 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
306
306
307 # Highlight matching brackets, but only when this setting is
307 # Highlight matching brackets, but only when this setting is
308 # enabled, and only when the DEFAULT_BUFFER has the focus.
308 # enabled, and only when the DEFAULT_BUFFER has the focus.
309 'extra_input_processors': [ConditionalProcessor(
309 'extra_input_processors': [ConditionalProcessor(
310 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
310 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
311 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
311 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
312 Condition(lambda cli: self.highlight_matching_brackets))],
312 Condition(lambda cli: self.highlight_matching_brackets))],
313 }
313 }
314
314
315 def _update_layout(self):
315 def _update_layout(self):
316 """
316 """
317 Ask for a re computation of the application layout, if for example ,
317 Ask for a re computation of the application layout, if for example ,
318 some configuration options have changed.
318 some configuration options have changed.
319 """
319 """
320 if self._pt_app:
320 if self._pt_app:
321 self._pt_app.layout = create_prompt_layout(**self._layout_options())
321 self._pt_app.layout = create_prompt_layout(**self._layout_options())
322
322
323 def prompt_for_code(self):
323 def prompt_for_code(self):
324 document = self.pt_cli.run(
324 document = self.pt_cli.run(
325 pre_run=self.pre_prompt, reset_current_buffer=True)
325 pre_run=self.pre_prompt, reset_current_buffer=True)
326 return document.text
326 return document.text
327
327
328 def init_io(self):
328 def init_io(self):
329 if sys.platform not in {'win32', 'cli'}:
329 if sys.platform not in {'win32', 'cli'}:
330 return
330 return
331
331
332 import win_unicode_console
332 import win_unicode_console
333 import colorama
333 import colorama
334
334
335 win_unicode_console.enable()
335 win_unicode_console.enable()
336 colorama.init()
336 colorama.init()
337
337
338 # For some reason we make these wrappers around stdout/stderr.
338 # For some reason we make these wrappers around stdout/stderr.
339 # For now, we need to reset them so all output gets coloured.
339 # For now, we need to reset them so all output gets coloured.
340 # https://github.com/ipython/ipython/issues/8669
340 # https://github.com/ipython/ipython/issues/8669
341 from IPython.utils import io
341 from IPython.utils import io
342 io.stdout = io.IOStream(sys.stdout)
342 io.stdout = io.IOStream(sys.stdout)
343 io.stderr = io.IOStream(sys.stderr)
343 io.stderr = io.IOStream(sys.stderr)
344
344
345 def init_magics(self):
345 def init_magics(self):
346 super(TerminalInteractiveShell, self).init_magics()
346 super(TerminalInteractiveShell, self).init_magics()
347 self.register_magics(TerminalMagics)
347 self.register_magics(TerminalMagics)
348
348
349 def init_alias(self):
349 def init_alias(self):
350 # The parent class defines aliases that can be safely used with any
350 # The parent class defines aliases that can be safely used with any
351 # frontend.
351 # frontend.
352 super(TerminalInteractiveShell, self).init_alias()
352 super(TerminalInteractiveShell, self).init_alias()
353
353
354 # Now define aliases that only make sense on the terminal, because they
354 # Now define aliases that only make sense on the terminal, because they
355 # need direct access to the console in a way that we can't emulate in
355 # need direct access to the console in a way that we can't emulate in
356 # GUI or web frontend
356 # GUI or web frontend
357 if os.name == 'posix':
357 if os.name == 'posix':
358 for cmd in ['clear', 'more', 'less', 'man']:
358 for cmd in ['clear', 'more', 'less', 'man']:
359 self.alias_manager.soft_define_alias(cmd, cmd)
359 self.alias_manager.soft_define_alias(cmd, cmd)
360
360
361
361
362 def __init__(self, *args, **kwargs):
362 def __init__(self, *args, **kwargs):
363 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
363 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
364 self.init_prompt_toolkit_cli()
364 self.init_prompt_toolkit_cli()
365 self.init_term_title()
365 self.init_term_title()
366 self.keep_running = True
366 self.keep_running = True
367
367
368 self.debugger_history = InMemoryHistory()
368 self.debugger_history = InMemoryHistory()
369
369
370 def ask_exit(self):
370 def ask_exit(self):
371 self.keep_running = False
371 self.keep_running = False
372
372
373 rl_next_input = None
373 rl_next_input = None
374
374
375 def pre_prompt(self):
375 def pre_prompt(self):
376 if self.rl_next_input:
376 if self.rl_next_input:
377 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
377 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
378 self.rl_next_input = None
378 self.rl_next_input = None
379
379
380 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
380 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
381
381
382 if display_banner is not DISPLAY_BANNER_DEPRECATED:
382 if display_banner is not DISPLAY_BANNER_DEPRECATED:
383 warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
383 warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
384
384
385 while self.keep_running:
385 while self.keep_running:
386 print(self.separate_in, end='')
386 print(self.separate_in, end='')
387
387
388 try:
388 try:
389 code = self.prompt_for_code()
389 code = self.prompt_for_code()
390 except EOFError:
390 except EOFError:
391 if (not self.confirm_exit) \
391 if (not self.confirm_exit) \
392 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
392 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
393 self.ask_exit()
393 self.ask_exit()
394
394
395 else:
395 else:
396 if code:
396 if code:
397 self.run_cell(code, store_history=True)
397 self.run_cell(code, store_history=True)
398
398
399 def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
399 def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
400 # An extra layer of protection in case someone mashing Ctrl-C breaks
400 # An extra layer of protection in case someone mashing Ctrl-C breaks
401 # out of our internal code.
401 # out of our internal code.
402 if display_banner is not DISPLAY_BANNER_DEPRECATED:
402 if display_banner is not DISPLAY_BANNER_DEPRECATED:
403 warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
403 warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
404 while True:
404 while True:
405 try:
405 try:
406 self.interact()
406 self.interact()
407 break
407 break
408 except KeyboardInterrupt:
408 except KeyboardInterrupt:
409 print("\nKeyboardInterrupt escaped interact()\n")
409 print("\nKeyboardInterrupt escaped interact()\n")
410
410
411 if hasattr(self, '_eventloop'):
411 if hasattr(self, '_eventloop'):
412 self._eventloop.close()
412 self._eventloop.close()
413
413
414 _inputhook = None
414 _inputhook = None
415 def inputhook(self, context):
415 def inputhook(self, context):
416 if self._inputhook is not None:
416 if self._inputhook is not None:
417 self._inputhook(context)
417 self._inputhook(context)
418
418
419 def enable_gui(self, gui=None):
419 def enable_gui(self, gui=None):
420 if gui:
420 if gui:
421 self._inputhook = get_inputhook_func(gui)
421 self._inputhook = get_inputhook_func(gui)
422 else:
422 else:
423 self._inputhook = None
423 self._inputhook = None
424
424
425 # Run !system commands directly, not through pipes, so terminal programs
425 # Run !system commands directly, not through pipes, so terminal programs
426 # work correctly.
426 # work correctly.
427 system = InteractiveShell.system_raw
427 system = InteractiveShell.system_raw
428
428
429 def auto_rewrite_input(self, cmd):
429 def auto_rewrite_input(self, cmd):
430 """Overridden from the parent class to use fancy rewriting prompt"""
430 """Overridden from the parent class to use fancy rewriting prompt"""
431 if not self.show_rewritten_input:
431 if not self.show_rewritten_input:
432 return
432 return
433
433
434 tokens = self.prompts.rewrite_prompt_tokens()
434 tokens = self.prompts.rewrite_prompt_tokens()
435 if self.pt_cli:
435 if self.pt_cli:
436 self.pt_cli.print_tokens(tokens)
436 self.pt_cli.print_tokens(tokens)
437 print(cmd)
437 print(cmd)
438 else:
438 else:
439 prompt = ''.join(s for t, s in tokens)
439 prompt = ''.join(s for t, s in tokens)
440 print(prompt, cmd, sep='')
440 print(prompt, cmd, sep='')
441
441
442 _prompts_before = None
442 _prompts_before = None
443 def switch_doctest_mode(self, mode):
443 def switch_doctest_mode(self, mode):
444 """Switch prompts to classic for %doctest_mode"""
444 """Switch prompts to classic for %doctest_mode"""
445 if mode:
445 if mode:
446 self._prompts_before = self.prompts
446 self._prompts_before = self.prompts
447 self.prompts = ClassicPrompts(self)
447 self.prompts = ClassicPrompts(self)
448 elif self._prompts_before:
448 elif self._prompts_before:
449 self.prompts = self._prompts_before
449 self.prompts = self._prompts_before
450 self._prompts_before = None
450 self._prompts_before = None
451 self._update_layout()
451 self._update_layout()
452
452
453
453
454 InteractiveShellABC.register(TerminalInteractiveShell)
454 InteractiveShellABC.register(TerminalInteractiveShell)
455
455
456 if __name__ == '__main__':
456 if __name__ == '__main__':
457 TerminalInteractiveShell.instance().interact()
457 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now