##// END OF EJS Templates
Use new prompt machinery to generate Out prompts
Thomas Kluyver -
Show More
@@ -1,293 +1,293 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Displayhook for IPython.
3 3
4 4 This defines a callable class that IPython uses for `sys.displayhook`.
5 5 """
6 6
7 7 # Copyright (c) IPython Development Team.
8 8 # Distributed under the terms of the Modified BSD License.
9 9
10 10 from __future__ import print_function
11 11
12 12 import sys
13 13 import io as _io
14 14 import tokenize
15 15
16 16 from traitlets.config.configurable import Configurable
17 17 from IPython.utils.py3compat import builtin_mod, cast_unicode_py2
18 18 from traitlets import Instance, Float
19 19 from warnings import warn
20 20
21 21 # TODO: Move the various attributes (cache_size, [others now moved]). Some
22 22 # of these are also attributes of InteractiveShell. They should be on ONE object
23 23 # only and the other objects should ask that one object for their values.
24 24
25 25 class DisplayHook(Configurable):
26 26 """The custom IPython displayhook to replace sys.displayhook.
27 27
28 28 This class does many things, but the basic idea is that it is a callable
29 29 that gets called anytime user code returns a value.
30 30 """
31 31
32 32 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
33 33 allow_none=True)
34 34 exec_result = Instance('IPython.core.interactiveshell.ExecutionResult',
35 35 allow_none=True)
36 36 cull_fraction = Float(0.2)
37 37
38 38 def __init__(self, shell=None, cache_size=1000, **kwargs):
39 39 super(DisplayHook, self).__init__(shell=shell, **kwargs)
40 40 cache_size_min = 3
41 41 if cache_size <= 0:
42 42 self.do_full_cache = 0
43 43 cache_size = 0
44 44 elif cache_size < cache_size_min:
45 45 self.do_full_cache = 0
46 46 cache_size = 0
47 47 warn('caching was disabled (min value for cache size is %s).' %
48 48 cache_size_min,level=3)
49 49 else:
50 50 self.do_full_cache = 1
51 51
52 52 self.cache_size = cache_size
53 53
54 54 # we need a reference to the user-level namespace
55 55 self.shell = shell
56 56
57 57 self._,self.__,self.___ = '','',''
58 58
59 59 # these are deliberately global:
60 60 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
61 61 self.shell.user_ns.update(to_user_ns)
62 62
63 63 @property
64 64 def prompt_count(self):
65 65 return self.shell.execution_count
66 66
67 67 #-------------------------------------------------------------------------
68 68 # Methods used in __call__. Override these methods to modify the behavior
69 69 # of the displayhook.
70 70 #-------------------------------------------------------------------------
71 71
72 72 def check_for_underscore(self):
73 73 """Check if the user has set the '_' variable by hand."""
74 74 # If something injected a '_' variable in __builtin__, delete
75 75 # ipython's automatic one so we don't clobber that. gettext() in
76 76 # particular uses _, so we need to stay away from it.
77 77 if '_' in builtin_mod.__dict__:
78 78 try:
79 79 del self.shell.user_ns['_']
80 80 except KeyError:
81 81 pass
82 82
83 83 def quiet(self):
84 84 """Should we silence the display hook because of ';'?"""
85 85 # do not print output if input ends in ';'
86 86
87 87 try:
88 88 cell = cast_unicode_py2(self.shell.history_manager.input_hist_parsed[-1])
89 89 except IndexError:
90 90 # some uses of ipshellembed may fail here
91 91 return False
92 92
93 93 sio = _io.StringIO(cell)
94 94 tokens = list(tokenize.generate_tokens(sio.readline))
95 95
96 96 for token in reversed(tokens):
97 97 if token[0] in (tokenize.ENDMARKER, tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT):
98 98 continue
99 99 if (token[0] == tokenize.OP) and (token[1] == ';'):
100 100 return True
101 101 else:
102 102 return False
103 103
104 104 def start_displayhook(self):
105 105 """Start the displayhook, initializing resources."""
106 106 pass
107 107
108 108 def write_output_prompt(self):
109 109 """Write the output prompt.
110 110
111 111 The default implementation simply writes the prompt to
112 112 ``io.stdout``.
113 113 """
114 114 # Use write, not print which adds an extra space.
115 115 sys.stdout.write(self.shell.separate_out)
116 outprompt = self.shell.prompt_manager.render('out')
116 outprompt = 'Out[{}]: '.format(self.shell.execution_count)
117 117 if self.do_full_cache:
118 118 sys.stdout.write(outprompt)
119 119
120 120 def compute_format_data(self, result):
121 121 """Compute format data of the object to be displayed.
122 122
123 123 The format data is a generalization of the :func:`repr` of an object.
124 124 In the default implementation the format data is a :class:`dict` of
125 125 key value pair where the keys are valid MIME types and the values
126 126 are JSON'able data structure containing the raw data for that MIME
127 127 type. It is up to frontends to determine pick a MIME to to use and
128 128 display that data in an appropriate manner.
129 129
130 130 This method only computes the format data for the object and should
131 131 NOT actually print or write that to a stream.
132 132
133 133 Parameters
134 134 ----------
135 135 result : object
136 136 The Python object passed to the display hook, whose format will be
137 137 computed.
138 138
139 139 Returns
140 140 -------
141 141 (format_dict, md_dict) : dict
142 142 format_dict is a :class:`dict` whose keys are valid MIME types and values are
143 143 JSON'able raw data for that MIME type. It is recommended that
144 144 all return values of this should always include the "text/plain"
145 145 MIME type representation of the object.
146 146 md_dict is a :class:`dict` with the same MIME type keys
147 147 of metadata associated with each output.
148 148
149 149 """
150 150 return self.shell.display_formatter.format(result)
151 151
152 152 def write_format_data(self, format_dict, md_dict=None):
153 153 """Write the format data dict to the frontend.
154 154
155 155 This default version of this method simply writes the plain text
156 156 representation of the object to ``io.stdout``. Subclasses should
157 157 override this method to send the entire `format_dict` to the
158 158 frontends.
159 159
160 160 Parameters
161 161 ----------
162 162 format_dict : dict
163 163 The format dict for the object passed to `sys.displayhook`.
164 164 md_dict : dict (optional)
165 165 The metadata dict to be associated with the display data.
166 166 """
167 167 if 'text/plain' not in format_dict:
168 168 # nothing to do
169 169 return
170 170 # We want to print because we want to always make sure we have a
171 171 # newline, even if all the prompt separators are ''. This is the
172 172 # standard IPython behavior.
173 173 result_repr = format_dict['text/plain']
174 174 if '\n' in result_repr:
175 175 # So that multi-line strings line up with the left column of
176 176 # the screen, instead of having the output prompt mess up
177 177 # their first line.
178 178 # We use the prompt template instead of the expanded prompt
179 179 # because the expansion may add ANSI escapes that will interfere
180 180 # with our ability to determine whether or not we should add
181 181 # a newline.
182 182 prompt_template = self.shell.prompt_manager.out_template
183 183 if prompt_template and not prompt_template.endswith('\n'):
184 184 # But avoid extraneous empty lines.
185 185 result_repr = '\n' + result_repr
186 186
187 187 print(result_repr)
188 188
189 189 def update_user_ns(self, result):
190 190 """Update user_ns with various things like _, __, _1, etc."""
191 191
192 192 # Avoid recursive reference when displaying _oh/Out
193 193 if result is not self.shell.user_ns['_oh']:
194 194 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
195 195 self.cull_cache()
196 196 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
197 197 # we cause buggy behavior for things like gettext).
198 198
199 199 if '_' not in builtin_mod.__dict__:
200 200 self.___ = self.__
201 201 self.__ = self._
202 202 self._ = result
203 203 self.shell.push({'_':self._,
204 204 '__':self.__,
205 205 '___':self.___}, interactive=False)
206 206
207 207 # hackish access to top-level namespace to create _1,_2... dynamically
208 208 to_main = {}
209 209 if self.do_full_cache:
210 210 new_result = '_'+repr(self.prompt_count)
211 211 to_main[new_result] = result
212 212 self.shell.push(to_main, interactive=False)
213 213 self.shell.user_ns['_oh'][self.prompt_count] = result
214 214
215 215 def fill_exec_result(self, result):
216 216 if self.exec_result is not None:
217 217 self.exec_result.result = result
218 218
219 219 def log_output(self, format_dict):
220 220 """Log the output."""
221 221 if 'text/plain' not in format_dict:
222 222 # nothing to do
223 223 return
224 224 if self.shell.logger.log_output:
225 225 self.shell.logger.log_write(format_dict['text/plain'], 'output')
226 226 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
227 227 format_dict['text/plain']
228 228
229 229 def finish_displayhook(self):
230 230 """Finish up all displayhook activities."""
231 231 sys.stdout.write(self.shell.separate_out2)
232 232 sys.stdout.flush()
233 233
234 234 def __call__(self, result=None):
235 235 """Printing with history cache management.
236 236
237 237 This is invoked everytime the interpreter needs to print, and is
238 238 activated by setting the variable sys.displayhook to it.
239 239 """
240 240 self.check_for_underscore()
241 241 if result is not None and not self.quiet():
242 242 self.start_displayhook()
243 243 self.write_output_prompt()
244 244 format_dict, md_dict = self.compute_format_data(result)
245 245 self.update_user_ns(result)
246 246 self.fill_exec_result(result)
247 247 if format_dict:
248 248 self.write_format_data(format_dict, md_dict)
249 249 self.log_output(format_dict)
250 250 self.finish_displayhook()
251 251
252 252 def cull_cache(self):
253 253 """Output cache is full, cull the oldest entries"""
254 254 oh = self.shell.user_ns.get('_oh', {})
255 255 sz = len(oh)
256 256 cull_count = max(int(sz * self.cull_fraction), 2)
257 257 warn('Output cache limit (currently {sz} entries) hit.\n'
258 258 'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
259 259
260 260 for i, n in enumerate(sorted(oh)):
261 261 if i >= cull_count:
262 262 break
263 263 self.shell.user_ns.pop('_%i' % n, None)
264 264 oh.pop(n, None)
265 265
266 266
267 267 def flush(self):
268 268 if not self.do_full_cache:
269 269 raise ValueError("You shouldn't have reached the cache flush "
270 270 "if full caching is not enabled!")
271 271 # delete auto-generated vars from global namespace
272 272
273 273 for n in range(1,self.prompt_count + 1):
274 274 key = '_'+repr(n)
275 275 try:
276 276 del self.shell.user_ns[key]
277 277 except: pass
278 278 # In some embedded circumstances, the user_ns doesn't have the
279 279 # '_oh' key set up.
280 280 oh = self.shell.user_ns.get('_oh', None)
281 281 if oh is not None:
282 282 oh.clear()
283 283
284 284 # Release our own references to objects:
285 285 self._, self.__, self.___ = '', '', ''
286 286
287 287 if '_' not in builtin_mod.__dict__:
288 288 self.shell.user_ns.update({'_':None,'__':None, '___':None})
289 289 import gc
290 290 # TODO: Is this really needed?
291 291 # IronPython blocks here forever
292 292 if sys.platform != "cli":
293 293 gc.collect()
@@ -1,36 +1,50 b''
1 1 from pygments.token import Token
2 import sys
3
4 from IPython.core.displayhook import DisplayHook
2 5
3 6 class Prompts(object):
4 7 def __init__(self, shell):
5 8 self.shell = shell
6 9
7 10 def in_prompt_tokens(self, cli=None):
8 11 return [
9 12 (Token.Prompt, 'In ['),
10 13 (Token.PromptNum, str(self.shell.execution_count)),
11 14 (Token.Prompt, ']: '),
12 15 ]
13 16
14 17 def _width(self):
15 18 in_tokens = self.in_prompt_tokens()
16 19 return sum(len(s) for (t, s) in in_tokens)
17 20
18 21 def continuation_prompt_tokens(self, cli=None, width=None):
19 22 if width is None:
20 23 width = self._width()
21 24 return [
22 25 (Token.Prompt, (' ' * (width - 5)) + '...: '),
23 26 ]
24 27
25 28 def rewrite_prompt_tokens(self):
26 29 width = self._width()
27 30 return [
28 31 (Token.Prompt, ('-' * (width - 2)) + '> '),
29 32 ]
30 33
31 34 def out_prompt_tokens(self):
32 35 return [
33 36 (Token.OutPrompt, 'Out['),
34 37 (Token.OutPromptNum, str(self.shell.execution_count)),
35 38 (Token.OutPrompt, ']: '),
36 39 ]
40
41 class RichPromptDisplayHook(DisplayHook):
42 """Subclass of base display hook using coloured prompt"""
43 def write_output_prompt(self):
44 sys.stdout.write(self.shell.separate_out)
45 if self.do_full_cache:
46 tokens = self.shell.prompts.out_prompt_tokens()
47 if self.shell.pt_cli:
48 self.shell.pt_cli.print_tokens(tokens)
49 else:
50 print(*(s for t, s in tokens), sep='')
@@ -1,451 +1,456 b''
1 1 """IPython terminal interface using prompt_toolkit in place of readline"""
2 2 from __future__ import print_function
3 3
4 4 import os
5 5 import sys
6 6 import signal
7 7 from warnings import warn
8 8
9 9 from IPython.core.error import TryNext
10 10 from IPython.core.interactiveshell import InteractiveShell
11 11 from IPython.utils.py3compat import cast_unicode_py2, input
12 12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
13 13 from IPython.utils.process import abbrev_cwd
14 14 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance
15 15
16 16 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
17 17 from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone
18 18 from prompt_toolkit.history import InMemoryHistory
19 19 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout
20 20 from prompt_toolkit.interface import CommandLineInterface
21 21 from prompt_toolkit.key_binding.manager import KeyBindingManager
22 22 from prompt_toolkit.keys import Keys
23 23 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
24 24 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
25 25
26 26 from pygments.styles import get_style_by_name, get_all_styles
27 27 from pygments.token import Token
28 28
29 29 from .debugger import TerminalPdb, Pdb
30 30 from .pt_inputhooks import get_inputhook_func
31 31 from .interactiveshell import get_default_editor, TerminalMagics
32 from .prompts import Prompts
32 from .prompts import Prompts, RichPromptDisplayHook
33 33 from .ptutils import IPythonPTCompleter, IPythonPTLexer
34 34
35 35 _use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty()
36 36
37 37 class TerminalInteractiveShell(InteractiveShell):
38 38 colors_force = True
39 39
40 40 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
41 41 'to reserve for the completion menu'
42 42 ).tag(config=True)
43 43
44 44 def _space_for_menu_changed(self, old, new):
45 45 self._update_layout()
46 46
47 47 pt_cli = None
48 48 debugger_history = None
49 49
50 50 simple_prompt = Bool(_use_simple_prompt,
51 51 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
52 52
53 53 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
54 54 IPython own testing machinery, and emacs inferior-shell integration through elpy.
55 55
56 56 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
57 57 environment variable is set, or the current terminal is not a tty.
58 58
59 59 """
60 60 ).tag(config=True)
61 61
62 62 @property
63 63 def debugger_cls(self):
64 64 return Pdb if self.simple_prompt else TerminalPdb
65 65
66 66 autoedit_syntax = Bool(False,
67 67 help="auto editing of files with syntax errors.",
68 68 ).tag(config=True)
69 69
70 70
71 71 confirm_exit = Bool(True,
72 72 help="""
73 73 Set to confirm when you try to exit IPython with an EOF (Control-D
74 74 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
75 75 you can force a direct exit without any confirmation.""",
76 76 ).tag(config=True)
77 77
78 78 editing_mode = Unicode('emacs',
79 79 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
80 80 ).tag(config=True)
81 81
82 82 mouse_support = Bool(False,
83 83 help="Enable mouse support in the prompt"
84 84 ).tag(config=True)
85 85
86 86 highlighting_style = Unicode('default',
87 87 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
88 88 ).tag(config=True)
89 89
90 90
91 91 @observe('highlighting_style')
92 92 def _highlighting_style_changed(self, change):
93 93 self._style = self._make_style_from_name(self.highlighting_style)
94 94
95 95 highlighting_style_overrides = Dict(
96 96 help="Override highlighting format for specific tokens"
97 97 ).tag(config=True)
98 98
99 99 editor = Unicode(get_default_editor(),
100 100 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
101 101 ).tag(config=True)
102 102
103 103 prompts = Instance(Prompts)
104 104
105 105 def _prompts_default(self):
106 106 return Prompts(self)
107 107
108 def _displayhook_class_default(self):
109 return RichPromptDisplayHook
110
108 111 term_title = Bool(True,
109 112 help="Automatically set the terminal title"
110 113 ).tag(config=True)
111 114
112 115 display_completions_in_columns = Bool(False,
113 116 help="Display a multi column completion menu.",
114 117 ).tag(config=True)
115 118
116 119 highlight_matching_brackets = Bool(True,
117 120 help="Highlight matching brackets .",
118 121 ).tag(config=True)
119 122
120 123 @observe('term_title')
121 124 def init_term_title(self, change=None):
122 125 # Enable or disable the terminal title.
123 126 if self.term_title:
124 127 toggle_set_term_title(True)
125 128 set_term_title('IPython: ' + abbrev_cwd())
126 129 else:
127 130 toggle_set_term_title(False)
128 131
129 132 def init_prompt_toolkit_cli(self):
130 133 if self.simple_prompt:
131 134 # Fall back to plain non-interactive output for tests.
132 135 # This is very limited, and only accepts a single line.
133 136 def prompt():
134 137 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
135 138 self.prompt_for_code = prompt
136 139 return
137 140
138 141 kbmanager = KeyBindingManager.for_prompt()
139 142 insert_mode = ViInsertMode() | EmacsInsertMode()
140 143 # Ctrl+J == Enter, seemingly
141 144 @kbmanager.registry.add_binding(Keys.ControlJ,
142 145 filter=(HasFocus(DEFAULT_BUFFER)
143 146 & ~HasSelection()
144 147 & insert_mode
145 148 ))
146 149 def _(event):
147 150 b = event.current_buffer
148 151 d = b.document
149 152 if not (d.on_last_line or d.cursor_position_row >= d.line_count
150 153 - d.empty_line_count_at_the_end()):
151 154 b.newline()
152 155 return
153 156
154 157 status, indent = self.input_splitter.check_complete(d.text)
155 158
156 159 if (status != 'incomplete') and b.accept_action.is_returnable:
157 160 b.accept_action.validate_and_handle(event.cli, b)
158 161 else:
159 162 b.insert_text('\n' + (' ' * (indent or 0)))
160 163
161 164 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER))
162 165 def _reset_buffer(event):
163 166 event.current_buffer.reset()
164 167
165 168 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER))
166 169 def _reset_search_buffer(event):
167 170 if event.current_buffer.document.text:
168 171 event.current_buffer.reset()
169 172 else:
170 173 event.cli.push_focus(DEFAULT_BUFFER)
171 174
172 175 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
173 176
174 177 @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
175 178 def _suspend_to_bg(event):
176 179 event.cli.suspend_to_background()
177 180
178 181 @Condition
179 182 def cursor_in_leading_ws(cli):
180 183 before = cli.application.buffer.document.current_line_before_cursor
181 184 return (not before) or before.isspace()
182 185
183 186 # Ctrl+I == Tab
184 187 @kbmanager.registry.add_binding(Keys.ControlI,
185 188 filter=(HasFocus(DEFAULT_BUFFER)
186 189 & ~HasSelection()
187 190 & insert_mode
188 191 & cursor_in_leading_ws
189 192 ))
190 193 def _indent_buffer(event):
191 194 event.current_buffer.insert_text(' ' * 4)
192 195
193 196 # Pre-populate history from IPython's history database
194 197 history = InMemoryHistory()
195 198 last_cell = u""
196 199 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
197 200 include_latest=True):
198 201 # Ignore blank lines and consecutive duplicates
199 202 cell = cell.rstrip()
200 203 if cell and (cell != last_cell):
201 204 history.append(cell)
202 205
203 206 self._style = self._make_style_from_name(self.highlighting_style)
204 207 style = DynamicStyle(lambda: self._style)
205 208
206 209 editing_mode = getattr(EditingMode, self.editing_mode.upper())
207 210
208 211 self._app = create_prompt_application(
209 212 editing_mode=editing_mode,
210 213 key_bindings_registry=kbmanager.registry,
211 214 history=history,
212 215 completer=IPythonPTCompleter(self.Completer),
213 216 enable_history_search=True,
214 217 style=style,
215 218 mouse_support=self.mouse_support,
216 219 **self._layout_options()
217 220 )
218 221 self._eventloop = create_eventloop(self.inputhook)
219 222 self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop)
220 223
221 224 def _make_style_from_name(self, name):
222 225 """
223 226 Small wrapper that make an IPython compatible style from a style name
224 227
225 228 We need that to add style for prompt ... etc.
226 229 """
227 230 style_cls = get_style_by_name(name)
228 231 style_overrides = {
229 232 Token.Prompt: '#009900',
230 233 Token.PromptNum: '#00ff00 bold',
234 Token.OutPrompt: '#990000',
235 Token.OutPromptNum: '#ff0000 bold',
231 236 }
232 237 if name == 'default':
233 238 style_cls = get_style_by_name('default')
234 239 # The default theme needs to be visible on both a dark background
235 240 # and a light background, because we can't tell what the terminal
236 241 # looks like. These tweaks to the default theme help with that.
237 242 style_overrides.update({
238 243 Token.Number: '#007700',
239 244 Token.Operator: 'noinherit',
240 245 Token.String: '#BB6622',
241 246 Token.Name.Function: '#2080D0',
242 247 Token.Name.Class: 'bold #2080D0',
243 248 Token.Name.Namespace: 'bold #2080D0',
244 249 })
245 250 style_overrides.update(self.highlighting_style_overrides)
246 251 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
247 252 style_dict=style_overrides)
248 253
249 254 return style
250 255
251 256 def _layout_options(self):
252 257 """
253 258 Return the current layout option for the current Terminal InteractiveShell
254 259 """
255 260 return {
256 261 'lexer':IPythonPTLexer(),
257 262 'reserve_space_for_menu':self.space_for_menu,
258 263 'get_prompt_tokens':self.prompts.in_prompt_tokens,
259 264 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
260 265 'multiline':True,
261 266 'display_completions_in_columns': self.display_completions_in_columns,
262 267
263 268 # Highlight matching brackets, but only when this setting is
264 269 # enabled, and only when the DEFAULT_BUFFER has the focus.
265 270 'extra_input_processors': [ConditionalProcessor(
266 271 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
267 272 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
268 273 Condition(lambda cli: self.highlight_matching_brackets))],
269 274 }
270 275
271 276 def _update_layout(self):
272 277 """
273 278 Ask for a re computation of the application layout, if for example ,
274 279 some configuration options have changed.
275 280 """
276 281 self._app.layout = create_prompt_layout(**self._layout_options())
277 282
278 283 def prompt_for_code(self):
279 284 document = self.pt_cli.run(
280 285 pre_run=self.pre_prompt, reset_current_buffer=True)
281 286 return document.text
282 287
283 288 def init_io(self):
284 289 if sys.platform not in {'win32', 'cli'}:
285 290 return
286 291
287 292 import colorama
288 293 colorama.init()
289 294
290 295 # For some reason we make these wrappers around stdout/stderr.
291 296 # For now, we need to reset them so all output gets coloured.
292 297 # https://github.com/ipython/ipython/issues/8669
293 298 from IPython.utils import io
294 299 io.stdout = io.IOStream(sys.stdout)
295 300 io.stderr = io.IOStream(sys.stderr)
296 301
297 302 def init_magics(self):
298 303 super(TerminalInteractiveShell, self).init_magics()
299 304 self.register_magics(TerminalMagics)
300 305
301 306 def init_alias(self):
302 307 # The parent class defines aliases that can be safely used with any
303 308 # frontend.
304 309 super(TerminalInteractiveShell, self).init_alias()
305 310
306 311 # Now define aliases that only make sense on the terminal, because they
307 312 # need direct access to the console in a way that we can't emulate in
308 313 # GUI or web frontend
309 314 if os.name == 'posix':
310 315 for cmd in ['clear', 'more', 'less', 'man']:
311 316 self.alias_manager.soft_define_alias(cmd, cmd)
312 317
313 318
314 319 def __init__(self, *args, **kwargs):
315 320 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
316 321 self.init_prompt_toolkit_cli()
317 322 self.init_term_title()
318 323 self.keep_running = True
319 324
320 325 self.debugger_history = InMemoryHistory()
321 326
322 327 def ask_exit(self):
323 328 self.keep_running = False
324 329
325 330 rl_next_input = None
326 331
327 332 def pre_prompt(self):
328 333 if self.rl_next_input:
329 334 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
330 335 self.rl_next_input = None
331 336
332 337 def interact(self):
333 338 while self.keep_running:
334 339 print(self.separate_in, end='')
335 340
336 341 try:
337 342 code = self.prompt_for_code()
338 343 except EOFError:
339 344 if (not self.confirm_exit) \
340 345 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
341 346 self.ask_exit()
342 347
343 348 else:
344 349 if code:
345 350 self.run_cell(code, store_history=True)
346 351 if self.autoedit_syntax and self.SyntaxTB.last_syntax_error:
347 352 self.edit_syntax_error()
348 353
349 354 def mainloop(self):
350 355 # An extra layer of protection in case someone mashing Ctrl-C breaks
351 356 # out of our internal code.
352 357 while True:
353 358 try:
354 359 self.interact()
355 360 break
356 361 except KeyboardInterrupt:
357 362 print("\nKeyboardInterrupt escaped interact()\n")
358 363
359 364 if hasattr(self, '_eventloop'):
360 365 self._eventloop.close()
361 366
362 367 _inputhook = None
363 368 def inputhook(self, context):
364 369 if self._inputhook is not None:
365 370 self._inputhook(context)
366 371
367 372 def enable_gui(self, gui=None):
368 373 if gui:
369 374 self._inputhook = get_inputhook_func(gui)
370 375 else:
371 376 self._inputhook = None
372 377
373 378 # Methods to support auto-editing of SyntaxErrors:
374 379
375 380 def edit_syntax_error(self):
376 381 """The bottom half of the syntax error handler called in the main loop.
377 382
378 383 Loop until syntax error is fixed or user cancels.
379 384 """
380 385
381 386 while self.SyntaxTB.last_syntax_error:
382 387 # copy and clear last_syntax_error
383 388 err = self.SyntaxTB.clear_err_state()
384 389 if not self._should_recompile(err):
385 390 return
386 391 try:
387 392 # may set last_syntax_error again if a SyntaxError is raised
388 393 self.safe_execfile(err.filename, self.user_ns)
389 394 except:
390 395 self.showtraceback()
391 396 else:
392 397 try:
393 398 with open(err.filename) as f:
394 399 # This should be inside a display_trap block and I
395 400 # think it is.
396 401 sys.displayhook(f.read())
397 402 except:
398 403 self.showtraceback()
399 404
400 405 def _should_recompile(self, e):
401 406 """Utility routine for edit_syntax_error"""
402 407
403 408 if e.filename in ('<ipython console>', '<input>', '<string>',
404 409 '<console>', '<BackgroundJob compilation>',
405 410 None):
406 411 return False
407 412 try:
408 413 if (self.autoedit_syntax and
409 414 not self.ask_yes_no(
410 415 'Return to editor to correct syntax error? '
411 416 '[Y/n] ', 'y')):
412 417 return False
413 418 except EOFError:
414 419 return False
415 420
416 421 def int0(x):
417 422 try:
418 423 return int(x)
419 424 except TypeError:
420 425 return 0
421 426
422 427 # always pass integer line and offset values to editor hook
423 428 try:
424 429 self.hooks.fix_error_editor(e.filename,
425 430 int0(e.lineno), int0(e.offset),
426 431 e.msg)
427 432 except TryNext:
428 433 warn('Could not open editor')
429 434 return False
430 435 return True
431 436
432 437 # Run !system commands directly, not through pipes, so terminal programs
433 438 # work correctly.
434 439 system = InteractiveShell.system_raw
435 440
436 441 def auto_rewrite_input(self, cmd):
437 442 """Overridden from the parent class to use fancy rewriting prompt"""
438 443 if not self.show_rewritten_input:
439 444 return
440 445
441 446 tokens = self.prompts.rewrite_prompt_tokens()
442 447 if self.pt_cli:
443 448 self.pt_cli.print_tokens(tokens)
444 449 print(cmd)
445 450 else:
446 451 prompt = ''.join(s for t, s in tokens)
447 452 print(prompt, cmd, sep='')
448 453
449 454
450 455 if __name__ == '__main__':
451 456 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now