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