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