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