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