##// END OF EJS Templates
Inspect continuation prompt signature and pass only viable arguments. (#14274)...
M Bussonnier -
r28567:59eccb24 merge
parent child Browse files
Show More
@@ -1,993 +1,1010 b''
1 """IPython terminal interface using prompt_toolkit"""
1 """IPython terminal interface using prompt_toolkit"""
2
2
3 import os
3 import os
4 import sys
4 import sys
5 import inspect
5 from warnings import warn
6 from warnings import warn
6 from typing import Union as UnionType, Optional
7 from typing import Union as UnionType, Optional
7
8
8 from IPython.core.async_helpers import get_asyncio_loop
9 from IPython.core.async_helpers import get_asyncio_loop
9 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
10 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
10 from IPython.utils.py3compat import input
11 from IPython.utils.py3compat import input
11 from IPython.utils.terminal import toggle_set_term_title, set_term_title, restore_term_title
12 from IPython.utils.terminal import toggle_set_term_title, set_term_title, restore_term_title
12 from IPython.utils.process import abbrev_cwd
13 from IPython.utils.process import abbrev_cwd
13 from traitlets import (
14 from traitlets import (
14 Bool,
15 Bool,
15 Unicode,
16 Unicode,
16 Dict,
17 Dict,
17 Integer,
18 Integer,
18 List,
19 List,
19 observe,
20 observe,
20 Instance,
21 Instance,
21 Type,
22 Type,
22 default,
23 default,
23 Enum,
24 Enum,
24 Union,
25 Union,
25 Any,
26 Any,
26 validate,
27 validate,
27 Float,
28 Float,
28 )
29 )
29
30
30 from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
31 from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
31 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
32 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
32 from prompt_toolkit.filters import HasFocus, Condition, IsDone
33 from prompt_toolkit.filters import HasFocus, Condition, IsDone
33 from prompt_toolkit.formatted_text import PygmentsTokens
34 from prompt_toolkit.formatted_text import PygmentsTokens
34 from prompt_toolkit.history import History
35 from prompt_toolkit.history import History
35 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
36 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
36 from prompt_toolkit.output import ColorDepth
37 from prompt_toolkit.output import ColorDepth
37 from prompt_toolkit.patch_stdout import patch_stdout
38 from prompt_toolkit.patch_stdout import patch_stdout
38 from prompt_toolkit.shortcuts import PromptSession, CompleteStyle, print_formatted_text
39 from prompt_toolkit.shortcuts import PromptSession, CompleteStyle, print_formatted_text
39 from prompt_toolkit.styles import DynamicStyle, merge_styles
40 from prompt_toolkit.styles import DynamicStyle, merge_styles
40 from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
41 from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
41 from prompt_toolkit import __version__ as ptk_version
42 from prompt_toolkit import __version__ as ptk_version
42
43
43 from pygments.styles import get_style_by_name
44 from pygments.styles import get_style_by_name
44 from pygments.style import Style
45 from pygments.style import Style
45 from pygments.token import Token
46 from pygments.token import Token
46
47
47 from .debugger import TerminalPdb, Pdb
48 from .debugger import TerminalPdb, Pdb
48 from .magics import TerminalMagics
49 from .magics import TerminalMagics
49 from .pt_inputhooks import get_inputhook_name_and_func
50 from .pt_inputhooks import get_inputhook_name_and_func
50 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
51 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
51 from .ptutils import IPythonPTCompleter, IPythonPTLexer
52 from .ptutils import IPythonPTCompleter, IPythonPTLexer
52 from .shortcuts import (
53 from .shortcuts import (
53 KEY_BINDINGS,
54 KEY_BINDINGS,
54 create_ipython_shortcuts,
55 create_ipython_shortcuts,
55 create_identifier,
56 create_identifier,
56 RuntimeBinding,
57 RuntimeBinding,
57 add_binding,
58 add_binding,
58 )
59 )
59 from .shortcuts.filters import KEYBINDING_FILTERS, filter_from_string
60 from .shortcuts.filters import KEYBINDING_FILTERS, filter_from_string
60 from .shortcuts.auto_suggest import (
61 from .shortcuts.auto_suggest import (
61 NavigableAutoSuggestFromHistory,
62 NavigableAutoSuggestFromHistory,
62 AppendAutoSuggestionInAnyLine,
63 AppendAutoSuggestionInAnyLine,
63 )
64 )
64
65
65 PTK3 = ptk_version.startswith('3.')
66 PTK3 = ptk_version.startswith('3.')
66
67
67
68
68 class _NoStyle(Style): pass
69 class _NoStyle(Style):
69
70 pass
70
71
71
72
72 _style_overrides_light_bg = {
73 _style_overrides_light_bg = {
73 Token.Prompt: '#ansibrightblue',
74 Token.Prompt: '#ansibrightblue',
74 Token.PromptNum: '#ansiblue bold',
75 Token.PromptNum: '#ansiblue bold',
75 Token.OutPrompt: '#ansibrightred',
76 Token.OutPrompt: '#ansibrightred',
76 Token.OutPromptNum: '#ansired bold',
77 Token.OutPromptNum: '#ansired bold',
77 }
78 }
78
79
79 _style_overrides_linux = {
80 _style_overrides_linux = {
80 Token.Prompt: '#ansibrightgreen',
81 Token.Prompt: '#ansibrightgreen',
81 Token.PromptNum: '#ansigreen bold',
82 Token.PromptNum: '#ansigreen bold',
82 Token.OutPrompt: '#ansibrightred',
83 Token.OutPrompt: '#ansibrightred',
83 Token.OutPromptNum: '#ansired bold',
84 Token.OutPromptNum: '#ansired bold',
84 }
85 }
85
86
87
88 def _backward_compat_continuation_prompt_tokens(method, width: int, *, lineno: int):
89 """
90 Sagemath use custom prompt and we broke them in 8.19.
91 """
92 sig = inspect.signature(method)
93 if "lineno" in inspect.signature(method).parameters or any(
94 [p.kind == p.VAR_KEYWORD for p in sig.parameters.values()]
95 ):
96 return method(width, lineno=lineno)
97 else:
98 return method(width)
99
100
86 def get_default_editor():
101 def get_default_editor():
87 try:
102 try:
88 return os.environ['EDITOR']
103 return os.environ['EDITOR']
89 except KeyError:
104 except KeyError:
90 pass
105 pass
91 except UnicodeError:
106 except UnicodeError:
92 warn("$EDITOR environment variable is not pure ASCII. Using platform "
107 warn("$EDITOR environment variable is not pure ASCII. Using platform "
93 "default editor.")
108 "default editor.")
94
109
95 if os.name == 'posix':
110 if os.name == 'posix':
96 return 'vi' # the only one guaranteed to be there!
111 return 'vi' # the only one guaranteed to be there!
97 else:
112 else:
98 return "notepad" # same in Windows!
113 return "notepad" # same in Windows!
99
114
100
115
101 # conservatively check for tty
116 # conservatively check for tty
102 # overridden streams can result in things like:
117 # overridden streams can result in things like:
103 # - sys.stdin = None
118 # - sys.stdin = None
104 # - no isatty method
119 # - no isatty method
105 for _name in ('stdin', 'stdout', 'stderr'):
120 for _name in ('stdin', 'stdout', 'stderr'):
106 _stream = getattr(sys, _name)
121 _stream = getattr(sys, _name)
107 try:
122 try:
108 if not _stream or not hasattr(_stream, "isatty") or not _stream.isatty():
123 if not _stream or not hasattr(_stream, "isatty") or not _stream.isatty():
109 _is_tty = False
124 _is_tty = False
110 break
125 break
111 except ValueError:
126 except ValueError:
112 # stream is closed
127 # stream is closed
113 _is_tty = False
128 _is_tty = False
114 break
129 break
115 else:
130 else:
116 _is_tty = True
131 _is_tty = True
117
132
118
133
119 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
134 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
120
135
121 def black_reformat_handler(text_before_cursor):
136 def black_reformat_handler(text_before_cursor):
122 """
137 """
123 We do not need to protect against error,
138 We do not need to protect against error,
124 this is taken care at a higher level where any reformat error is ignored.
139 this is taken care at a higher level where any reformat error is ignored.
125 Indeed we may call reformatting on incomplete code.
140 Indeed we may call reformatting on incomplete code.
126 """
141 """
127 import black
142 import black
128
143
129 formatted_text = black.format_str(text_before_cursor, mode=black.FileMode())
144 formatted_text = black.format_str(text_before_cursor, mode=black.FileMode())
130 if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
145 if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
131 formatted_text = formatted_text[:-1]
146 formatted_text = formatted_text[:-1]
132 return formatted_text
147 return formatted_text
133
148
134
149
135 def yapf_reformat_handler(text_before_cursor):
150 def yapf_reformat_handler(text_before_cursor):
136 from yapf.yapflib import file_resources
151 from yapf.yapflib import file_resources
137 from yapf.yapflib import yapf_api
152 from yapf.yapflib import yapf_api
138
153
139 style_config = file_resources.GetDefaultStyleForDir(os.getcwd())
154 style_config = file_resources.GetDefaultStyleForDir(os.getcwd())
140 formatted_text, was_formatted = yapf_api.FormatCode(
155 formatted_text, was_formatted = yapf_api.FormatCode(
141 text_before_cursor, style_config=style_config
156 text_before_cursor, style_config=style_config
142 )
157 )
143 if was_formatted:
158 if was_formatted:
144 if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
159 if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
145 formatted_text = formatted_text[:-1]
160 formatted_text = formatted_text[:-1]
146 return formatted_text
161 return formatted_text
147 else:
162 else:
148 return text_before_cursor
163 return text_before_cursor
149
164
150
165
151 class PtkHistoryAdapter(History):
166 class PtkHistoryAdapter(History):
152 """
167 """
153 Prompt toolkit has it's own way of handling history, Where it assumes it can
168 Prompt toolkit has it's own way of handling history, Where it assumes it can
154 Push/pull from history.
169 Push/pull from history.
155
170
156 """
171 """
157
172
158 def __init__(self, shell):
173 def __init__(self, shell):
159 super().__init__()
174 super().__init__()
160 self.shell = shell
175 self.shell = shell
161 self._refresh()
176 self._refresh()
162
177
163 def append_string(self, string):
178 def append_string(self, string):
164 # we rely on sql for that.
179 # we rely on sql for that.
165 self._loaded = False
180 self._loaded = False
166 self._refresh()
181 self._refresh()
167
182
168 def _refresh(self):
183 def _refresh(self):
169 if not self._loaded:
184 if not self._loaded:
170 self._loaded_strings = list(self.load_history_strings())
185 self._loaded_strings = list(self.load_history_strings())
171
186
172 def load_history_strings(self):
187 def load_history_strings(self):
173 last_cell = ""
188 last_cell = ""
174 res = []
189 res = []
175 for __, ___, cell in self.shell.history_manager.get_tail(
190 for __, ___, cell in self.shell.history_manager.get_tail(
176 self.shell.history_load_length, include_latest=True
191 self.shell.history_load_length, include_latest=True
177 ):
192 ):
178 # Ignore blank lines and consecutive duplicates
193 # Ignore blank lines and consecutive duplicates
179 cell = cell.rstrip()
194 cell = cell.rstrip()
180 if cell and (cell != last_cell):
195 if cell and (cell != last_cell):
181 res.append(cell)
196 res.append(cell)
182 last_cell = cell
197 last_cell = cell
183 yield from res[::-1]
198 yield from res[::-1]
184
199
185 def store_string(self, string: str) -> None:
200 def store_string(self, string: str) -> None:
186 pass
201 pass
187
202
188 class TerminalInteractiveShell(InteractiveShell):
203 class TerminalInteractiveShell(InteractiveShell):
189 mime_renderers = Dict().tag(config=True)
204 mime_renderers = Dict().tag(config=True)
190
205
191 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
206 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
192 'to reserve for the tab completion menu, '
207 'to reserve for the tab completion menu, '
193 'search history, ...etc, the height of '
208 'search history, ...etc, the height of '
194 'these menus will at most this value. '
209 'these menus will at most this value. '
195 'Increase it is you prefer long and skinny '
210 'Increase it is you prefer long and skinny '
196 'menus, decrease for short and wide.'
211 'menus, decrease for short and wide.'
197 ).tag(config=True)
212 ).tag(config=True)
198
213
199 pt_app: UnionType[PromptSession, None] = None
214 pt_app: UnionType[PromptSession, None] = None
200 auto_suggest: UnionType[
215 auto_suggest: UnionType[
201 AutoSuggestFromHistory, NavigableAutoSuggestFromHistory, None
216 AutoSuggestFromHistory, NavigableAutoSuggestFromHistory, None
202 ] = None
217 ] = None
203 debugger_history = None
218 debugger_history = None
204
219
205 debugger_history_file = Unicode(
220 debugger_history_file = Unicode(
206 "~/.pdbhistory", help="File in which to store and read history"
221 "~/.pdbhistory", help="File in which to store and read history"
207 ).tag(config=True)
222 ).tag(config=True)
208
223
209 simple_prompt = Bool(_use_simple_prompt,
224 simple_prompt = Bool(_use_simple_prompt,
210 help="""Use `raw_input` for the REPL, without completion and prompt colors.
225 help="""Use `raw_input` for the REPL, without completion and prompt colors.
211
226
212 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
227 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
213 IPython own testing machinery, and emacs inferior-shell integration through elpy.
228 IPython own testing machinery, and emacs inferior-shell integration through elpy.
214
229
215 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
230 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
216 environment variable is set, or the current terminal is not a tty."""
231 environment variable is set, or the current terminal is not a tty."""
217 ).tag(config=True)
232 ).tag(config=True)
218
233
219 @property
234 @property
220 def debugger_cls(self):
235 def debugger_cls(self):
221 return Pdb if self.simple_prompt else TerminalPdb
236 return Pdb if self.simple_prompt else TerminalPdb
222
237
223 confirm_exit = Bool(True,
238 confirm_exit = Bool(True,
224 help="""
239 help="""
225 Set to confirm when you try to exit IPython with an EOF (Control-D
240 Set to confirm when you try to exit IPython with an EOF (Control-D
226 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
241 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
227 you can force a direct exit without any confirmation.""",
242 you can force a direct exit without any confirmation.""",
228 ).tag(config=True)
243 ).tag(config=True)
229
244
230 editing_mode = Unicode('emacs',
245 editing_mode = Unicode('emacs',
231 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
246 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
232 ).tag(config=True)
247 ).tag(config=True)
233
248
234 emacs_bindings_in_vi_insert_mode = Bool(
249 emacs_bindings_in_vi_insert_mode = Bool(
235 True,
250 True,
236 help="Add shortcuts from 'emacs' insert mode to 'vi' insert mode.",
251 help="Add shortcuts from 'emacs' insert mode to 'vi' insert mode.",
237 ).tag(config=True)
252 ).tag(config=True)
238
253
239 modal_cursor = Bool(
254 modal_cursor = Bool(
240 True,
255 True,
241 help="""
256 help="""
242 Cursor shape changes depending on vi mode: beam in vi insert mode,
257 Cursor shape changes depending on vi mode: beam in vi insert mode,
243 block in nav mode, underscore in replace mode.""",
258 block in nav mode, underscore in replace mode.""",
244 ).tag(config=True)
259 ).tag(config=True)
245
260
246 ttimeoutlen = Float(
261 ttimeoutlen = Float(
247 0.01,
262 0.01,
248 help="""The time in milliseconds that is waited for a key code
263 help="""The time in milliseconds that is waited for a key code
249 to complete.""",
264 to complete.""",
250 ).tag(config=True)
265 ).tag(config=True)
251
266
252 timeoutlen = Float(
267 timeoutlen = Float(
253 0.5,
268 0.5,
254 help="""The time in milliseconds that is waited for a mapped key
269 help="""The time in milliseconds that is waited for a mapped key
255 sequence to complete.""",
270 sequence to complete.""",
256 ).tag(config=True)
271 ).tag(config=True)
257
272
258 autoformatter = Unicode(
273 autoformatter = Unicode(
259 None,
274 None,
260 help="Autoformatter to reformat Terminal code. Can be `'black'`, `'yapf'` or `None`",
275 help="Autoformatter to reformat Terminal code. Can be `'black'`, `'yapf'` or `None`",
261 allow_none=True
276 allow_none=True
262 ).tag(config=True)
277 ).tag(config=True)
263
278
264 auto_match = Bool(
279 auto_match = Bool(
265 False,
280 False,
266 help="""
281 help="""
267 Automatically add/delete closing bracket or quote when opening bracket or quote is entered/deleted.
282 Automatically add/delete closing bracket or quote when opening bracket or quote is entered/deleted.
268 Brackets: (), [], {}
283 Brackets: (), [], {}
269 Quotes: '', \"\"
284 Quotes: '', \"\"
270 """,
285 """,
271 ).tag(config=True)
286 ).tag(config=True)
272
287
273 mouse_support = Bool(False,
288 mouse_support = Bool(False,
274 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
289 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
275 ).tag(config=True)
290 ).tag(config=True)
276
291
277 # We don't load the list of styles for the help string, because loading
292 # We don't load the list of styles for the help string, because loading
278 # Pygments plugins takes time and can cause unexpected errors.
293 # Pygments plugins takes time and can cause unexpected errors.
279 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
294 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
280 help="""The name or class of a Pygments style to use for syntax
295 help="""The name or class of a Pygments style to use for syntax
281 highlighting. To see available styles, run `pygmentize -L styles`."""
296 highlighting. To see available styles, run `pygmentize -L styles`."""
282 ).tag(config=True)
297 ).tag(config=True)
283
298
284 @validate('editing_mode')
299 @validate('editing_mode')
285 def _validate_editing_mode(self, proposal):
300 def _validate_editing_mode(self, proposal):
286 if proposal['value'].lower() == 'vim':
301 if proposal['value'].lower() == 'vim':
287 proposal['value']= 'vi'
302 proposal['value']= 'vi'
288 elif proposal['value'].lower() == 'default':
303 elif proposal['value'].lower() == 'default':
289 proposal['value']= 'emacs'
304 proposal['value']= 'emacs'
290
305
291 if hasattr(EditingMode, proposal['value'].upper()):
306 if hasattr(EditingMode, proposal['value'].upper()):
292 return proposal['value'].lower()
307 return proposal['value'].lower()
293
308
294 return self.editing_mode
309 return self.editing_mode
295
310
296 @observe('editing_mode')
311 @observe('editing_mode')
297 def _editing_mode(self, change):
312 def _editing_mode(self, change):
298 if self.pt_app:
313 if self.pt_app:
299 self.pt_app.editing_mode = getattr(EditingMode, change.new.upper())
314 self.pt_app.editing_mode = getattr(EditingMode, change.new.upper())
300
315
301 def _set_formatter(self, formatter):
316 def _set_formatter(self, formatter):
302 if formatter is None:
317 if formatter is None:
303 self.reformat_handler = lambda x:x
318 self.reformat_handler = lambda x:x
304 elif formatter == 'black':
319 elif formatter == 'black':
305 self.reformat_handler = black_reformat_handler
320 self.reformat_handler = black_reformat_handler
306 elif formatter == "yapf":
321 elif formatter == "yapf":
307 self.reformat_handler = yapf_reformat_handler
322 self.reformat_handler = yapf_reformat_handler
308 else:
323 else:
309 raise ValueError
324 raise ValueError
310
325
311 @observe("autoformatter")
326 @observe("autoformatter")
312 def _autoformatter_changed(self, change):
327 def _autoformatter_changed(self, change):
313 formatter = change.new
328 formatter = change.new
314 self._set_formatter(formatter)
329 self._set_formatter(formatter)
315
330
316 @observe('highlighting_style')
331 @observe('highlighting_style')
317 @observe('colors')
332 @observe('colors')
318 def _highlighting_style_changed(self, change):
333 def _highlighting_style_changed(self, change):
319 self.refresh_style()
334 self.refresh_style()
320
335
321 def refresh_style(self):
336 def refresh_style(self):
322 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
337 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
323
338
324 highlighting_style_overrides = Dict(
339 highlighting_style_overrides = Dict(
325 help="Override highlighting format for specific tokens"
340 help="Override highlighting format for specific tokens"
326 ).tag(config=True)
341 ).tag(config=True)
327
342
328 true_color = Bool(False,
343 true_color = Bool(False,
329 help="""Use 24bit colors instead of 256 colors in prompt highlighting.
344 help="""Use 24bit colors instead of 256 colors in prompt highlighting.
330 If your terminal supports true color, the following command should
345 If your terminal supports true color, the following command should
331 print ``TRUECOLOR`` in orange::
346 print ``TRUECOLOR`` in orange::
332
347
333 printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"
348 printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"
334 """,
349 """,
335 ).tag(config=True)
350 ).tag(config=True)
336
351
337 editor = Unicode(get_default_editor(),
352 editor = Unicode(get_default_editor(),
338 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
353 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
339 ).tag(config=True)
354 ).tag(config=True)
340
355
341 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
356 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
342
357
343 prompts = Instance(Prompts)
358 prompts = Instance(Prompts)
344
359
345 @default('prompts')
360 @default('prompts')
346 def _prompts_default(self):
361 def _prompts_default(self):
347 return self.prompts_class(self)
362 return self.prompts_class(self)
348
363
349 # @observe('prompts')
364 # @observe('prompts')
350 # def _(self, change):
365 # def _(self, change):
351 # self._update_layout()
366 # self._update_layout()
352
367
353 @default('displayhook_class')
368 @default('displayhook_class')
354 def _displayhook_class_default(self):
369 def _displayhook_class_default(self):
355 return RichPromptDisplayHook
370 return RichPromptDisplayHook
356
371
357 term_title = Bool(True,
372 term_title = Bool(True,
358 help="Automatically set the terminal title"
373 help="Automatically set the terminal title"
359 ).tag(config=True)
374 ).tag(config=True)
360
375
361 term_title_format = Unicode("IPython: {cwd}",
376 term_title_format = Unicode("IPython: {cwd}",
362 help="Customize the terminal title format. This is a python format string. " +
377 help="Customize the terminal title format. This is a python format string. " +
363 "Available substitutions are: {cwd}."
378 "Available substitutions are: {cwd}."
364 ).tag(config=True)
379 ).tag(config=True)
365
380
366 display_completions = Enum(('column', 'multicolumn','readlinelike'),
381 display_completions = Enum(('column', 'multicolumn','readlinelike'),
367 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
382 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
368 "'readlinelike'. These options are for `prompt_toolkit`, see "
383 "'readlinelike'. These options are for `prompt_toolkit`, see "
369 "`prompt_toolkit` documentation for more information."
384 "`prompt_toolkit` documentation for more information."
370 ),
385 ),
371 default_value='multicolumn').tag(config=True)
386 default_value='multicolumn').tag(config=True)
372
387
373 highlight_matching_brackets = Bool(True,
388 highlight_matching_brackets = Bool(True,
374 help="Highlight matching brackets.",
389 help="Highlight matching brackets.",
375 ).tag(config=True)
390 ).tag(config=True)
376
391
377 extra_open_editor_shortcuts = Bool(False,
392 extra_open_editor_shortcuts = Bool(False,
378 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
393 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
379 "This is in addition to the F2 binding, which is always enabled."
394 "This is in addition to the F2 binding, which is always enabled."
380 ).tag(config=True)
395 ).tag(config=True)
381
396
382 handle_return = Any(None,
397 handle_return = Any(None,
383 help="Provide an alternative handler to be called when the user presses "
398 help="Provide an alternative handler to be called when the user presses "
384 "Return. This is an advanced option intended for debugging, which "
399 "Return. This is an advanced option intended for debugging, which "
385 "may be changed or removed in later releases."
400 "may be changed or removed in later releases."
386 ).tag(config=True)
401 ).tag(config=True)
387
402
388 enable_history_search = Bool(True,
403 enable_history_search = Bool(True,
389 help="Allows to enable/disable the prompt toolkit history search"
404 help="Allows to enable/disable the prompt toolkit history search"
390 ).tag(config=True)
405 ).tag(config=True)
391
406
392 autosuggestions_provider = Unicode(
407 autosuggestions_provider = Unicode(
393 "NavigableAutoSuggestFromHistory",
408 "NavigableAutoSuggestFromHistory",
394 help="Specifies from which source automatic suggestions are provided. "
409 help="Specifies from which source automatic suggestions are provided. "
395 "Can be set to ``'NavigableAutoSuggestFromHistory'`` (:kbd:`up` and "
410 "Can be set to ``'NavigableAutoSuggestFromHistory'`` (:kbd:`up` and "
396 ":kbd:`down` swap suggestions), ``'AutoSuggestFromHistory'``, "
411 ":kbd:`down` swap suggestions), ``'AutoSuggestFromHistory'``, "
397 " or ``None`` to disable automatic suggestions. "
412 " or ``None`` to disable automatic suggestions. "
398 "Default is `'NavigableAutoSuggestFromHistory`'.",
413 "Default is `'NavigableAutoSuggestFromHistory`'.",
399 allow_none=True,
414 allow_none=True,
400 ).tag(config=True)
415 ).tag(config=True)
401
416
402 def _set_autosuggestions(self, provider):
417 def _set_autosuggestions(self, provider):
403 # disconnect old handler
418 # disconnect old handler
404 if self.auto_suggest and isinstance(
419 if self.auto_suggest and isinstance(
405 self.auto_suggest, NavigableAutoSuggestFromHistory
420 self.auto_suggest, NavigableAutoSuggestFromHistory
406 ):
421 ):
407 self.auto_suggest.disconnect()
422 self.auto_suggest.disconnect()
408 if provider is None:
423 if provider is None:
409 self.auto_suggest = None
424 self.auto_suggest = None
410 elif provider == "AutoSuggestFromHistory":
425 elif provider == "AutoSuggestFromHistory":
411 self.auto_suggest = AutoSuggestFromHistory()
426 self.auto_suggest = AutoSuggestFromHistory()
412 elif provider == "NavigableAutoSuggestFromHistory":
427 elif provider == "NavigableAutoSuggestFromHistory":
413 self.auto_suggest = NavigableAutoSuggestFromHistory()
428 self.auto_suggest = NavigableAutoSuggestFromHistory()
414 else:
429 else:
415 raise ValueError("No valid provider.")
430 raise ValueError("No valid provider.")
416 if self.pt_app:
431 if self.pt_app:
417 self.pt_app.auto_suggest = self.auto_suggest
432 self.pt_app.auto_suggest = self.auto_suggest
418
433
419 @observe("autosuggestions_provider")
434 @observe("autosuggestions_provider")
420 def _autosuggestions_provider_changed(self, change):
435 def _autosuggestions_provider_changed(self, change):
421 provider = change.new
436 provider = change.new
422 self._set_autosuggestions(provider)
437 self._set_autosuggestions(provider)
423
438
424 shortcuts = List(
439 shortcuts = List(
425 trait=Dict(
440 trait=Dict(
426 key_trait=Enum(
441 key_trait=Enum(
427 [
442 [
428 "command",
443 "command",
429 "match_keys",
444 "match_keys",
430 "match_filter",
445 "match_filter",
431 "new_keys",
446 "new_keys",
432 "new_filter",
447 "new_filter",
433 "create",
448 "create",
434 ]
449 ]
435 ),
450 ),
436 per_key_traits={
451 per_key_traits={
437 "command": Unicode(),
452 "command": Unicode(),
438 "match_keys": List(Unicode()),
453 "match_keys": List(Unicode()),
439 "match_filter": Unicode(),
454 "match_filter": Unicode(),
440 "new_keys": List(Unicode()),
455 "new_keys": List(Unicode()),
441 "new_filter": Unicode(),
456 "new_filter": Unicode(),
442 "create": Bool(False),
457 "create": Bool(False),
443 },
458 },
444 ),
459 ),
445 help="""Add, disable or modifying shortcuts.
460 help="""Add, disable or modifying shortcuts.
446
461
447 Each entry on the list should be a dictionary with ``command`` key
462 Each entry on the list should be a dictionary with ``command`` key
448 identifying the target function executed by the shortcut and at least
463 identifying the target function executed by the shortcut and at least
449 one of the following:
464 one of the following:
450
465
451 - ``match_keys``: list of keys used to match an existing shortcut,
466 - ``match_keys``: list of keys used to match an existing shortcut,
452 - ``match_filter``: shortcut filter used to match an existing shortcut,
467 - ``match_filter``: shortcut filter used to match an existing shortcut,
453 - ``new_keys``: list of keys to set,
468 - ``new_keys``: list of keys to set,
454 - ``new_filter``: a new shortcut filter to set
469 - ``new_filter``: a new shortcut filter to set
455
470
456 The filters have to be composed of pre-defined verbs and joined by one
471 The filters have to be composed of pre-defined verbs and joined by one
457 of the following conjunctions: ``&`` (and), ``|`` (or), ``~`` (not).
472 of the following conjunctions: ``&`` (and), ``|`` (or), ``~`` (not).
458 The pre-defined verbs are:
473 The pre-defined verbs are:
459
474
460 {}
475 {}
461
476
462
477
463 To disable a shortcut set ``new_keys`` to an empty list.
478 To disable a shortcut set ``new_keys`` to an empty list.
464 To add a shortcut add key ``create`` with value ``True``.
479 To add a shortcut add key ``create`` with value ``True``.
465
480
466 When modifying/disabling shortcuts, ``match_keys``/``match_filter`` can
481 When modifying/disabling shortcuts, ``match_keys``/``match_filter`` can
467 be omitted if the provided specification uniquely identifies a shortcut
482 be omitted if the provided specification uniquely identifies a shortcut
468 to be modified/disabled. When modifying a shortcut ``new_filter`` or
483 to be modified/disabled. When modifying a shortcut ``new_filter`` or
469 ``new_keys`` can be omitted which will result in reuse of the existing
484 ``new_keys`` can be omitted which will result in reuse of the existing
470 filter/keys.
485 filter/keys.
471
486
472 Only shortcuts defined in IPython (and not default prompt-toolkit
487 Only shortcuts defined in IPython (and not default prompt-toolkit
473 shortcuts) can be modified or disabled. The full list of shortcuts,
488 shortcuts) can be modified or disabled. The full list of shortcuts,
474 command identifiers and filters is available under
489 command identifiers and filters is available under
475 :ref:`terminal-shortcuts-list`.
490 :ref:`terminal-shortcuts-list`.
476 """.format(
491 """.format(
477 "\n ".join([f"- `{k}`" for k in KEYBINDING_FILTERS])
492 "\n ".join([f"- `{k}`" for k in KEYBINDING_FILTERS])
478 ),
493 ),
479 ).tag(config=True)
494 ).tag(config=True)
480
495
481 @observe("shortcuts")
496 @observe("shortcuts")
482 def _shortcuts_changed(self, change):
497 def _shortcuts_changed(self, change):
483 if self.pt_app:
498 if self.pt_app:
484 self.pt_app.key_bindings = self._merge_shortcuts(user_shortcuts=change.new)
499 self.pt_app.key_bindings = self._merge_shortcuts(user_shortcuts=change.new)
485
500
486 def _merge_shortcuts(self, user_shortcuts):
501 def _merge_shortcuts(self, user_shortcuts):
487 # rebuild the bindings list from scratch
502 # rebuild the bindings list from scratch
488 key_bindings = create_ipython_shortcuts(self)
503 key_bindings = create_ipython_shortcuts(self)
489
504
490 # for now we only allow adding shortcuts for commands which are already
505 # for now we only allow adding shortcuts for commands which are already
491 # registered; this is a security precaution.
506 # registered; this is a security precaution.
492 known_commands = {
507 known_commands = {
493 create_identifier(binding.command): binding.command
508 create_identifier(binding.command): binding.command
494 for binding in KEY_BINDINGS
509 for binding in KEY_BINDINGS
495 }
510 }
496 shortcuts_to_skip = []
511 shortcuts_to_skip = []
497 shortcuts_to_add = []
512 shortcuts_to_add = []
498
513
499 for shortcut in user_shortcuts:
514 for shortcut in user_shortcuts:
500 command_id = shortcut["command"]
515 command_id = shortcut["command"]
501 if command_id not in known_commands:
516 if command_id not in known_commands:
502 allowed_commands = "\n - ".join(known_commands)
517 allowed_commands = "\n - ".join(known_commands)
503 raise ValueError(
518 raise ValueError(
504 f"{command_id} is not a known shortcut command."
519 f"{command_id} is not a known shortcut command."
505 f" Allowed commands are: \n - {allowed_commands}"
520 f" Allowed commands are: \n - {allowed_commands}"
506 )
521 )
507 old_keys = shortcut.get("match_keys", None)
522 old_keys = shortcut.get("match_keys", None)
508 old_filter = (
523 old_filter = (
509 filter_from_string(shortcut["match_filter"])
524 filter_from_string(shortcut["match_filter"])
510 if "match_filter" in shortcut
525 if "match_filter" in shortcut
511 else None
526 else None
512 )
527 )
513 matching = [
528 matching = [
514 binding
529 binding
515 for binding in KEY_BINDINGS
530 for binding in KEY_BINDINGS
516 if (
531 if (
517 (old_filter is None or binding.filter == old_filter)
532 (old_filter is None or binding.filter == old_filter)
518 and (old_keys is None or [k for k in binding.keys] == old_keys)
533 and (old_keys is None or [k for k in binding.keys] == old_keys)
519 and create_identifier(binding.command) == command_id
534 and create_identifier(binding.command) == command_id
520 )
535 )
521 ]
536 ]
522
537
523 new_keys = shortcut.get("new_keys", None)
538 new_keys = shortcut.get("new_keys", None)
524 new_filter = shortcut.get("new_filter", None)
539 new_filter = shortcut.get("new_filter", None)
525
540
526 command = known_commands[command_id]
541 command = known_commands[command_id]
527
542
528 creating_new = shortcut.get("create", False)
543 creating_new = shortcut.get("create", False)
529 modifying_existing = not creating_new and (
544 modifying_existing = not creating_new and (
530 new_keys is not None or new_filter
545 new_keys is not None or new_filter
531 )
546 )
532
547
533 if creating_new and new_keys == []:
548 if creating_new and new_keys == []:
534 raise ValueError("Cannot add a shortcut without keys")
549 raise ValueError("Cannot add a shortcut without keys")
535
550
536 if modifying_existing:
551 if modifying_existing:
537 specification = {
552 specification = {
538 key: shortcut[key]
553 key: shortcut[key]
539 for key in ["command", "filter"]
554 for key in ["command", "filter"]
540 if key in shortcut
555 if key in shortcut
541 }
556 }
542 if len(matching) == 0:
557 if len(matching) == 0:
543 raise ValueError(
558 raise ValueError(
544 f"No shortcuts matching {specification} found in {KEY_BINDINGS}"
559 f"No shortcuts matching {specification} found in {KEY_BINDINGS}"
545 )
560 )
546 elif len(matching) > 1:
561 elif len(matching) > 1:
547 raise ValueError(
562 raise ValueError(
548 f"Multiple shortcuts matching {specification} found,"
563 f"Multiple shortcuts matching {specification} found,"
549 f" please add keys/filter to select one of: {matching}"
564 f" please add keys/filter to select one of: {matching}"
550 )
565 )
551
566
552 matched = matching[0]
567 matched = matching[0]
553 old_filter = matched.filter
568 old_filter = matched.filter
554 old_keys = list(matched.keys)
569 old_keys = list(matched.keys)
555 shortcuts_to_skip.append(
570 shortcuts_to_skip.append(
556 RuntimeBinding(
571 RuntimeBinding(
557 command,
572 command,
558 keys=old_keys,
573 keys=old_keys,
559 filter=old_filter,
574 filter=old_filter,
560 )
575 )
561 )
576 )
562
577
563 if new_keys != []:
578 if new_keys != []:
564 shortcuts_to_add.append(
579 shortcuts_to_add.append(
565 RuntimeBinding(
580 RuntimeBinding(
566 command,
581 command,
567 keys=new_keys or old_keys,
582 keys=new_keys or old_keys,
568 filter=filter_from_string(new_filter)
583 filter=filter_from_string(new_filter)
569 if new_filter is not None
584 if new_filter is not None
570 else (
585 else (
571 old_filter
586 old_filter
572 if old_filter is not None
587 if old_filter is not None
573 else filter_from_string("always")
588 else filter_from_string("always")
574 ),
589 ),
575 )
590 )
576 )
591 )
577
592
578 # rebuild the bindings list from scratch
593 # rebuild the bindings list from scratch
579 key_bindings = create_ipython_shortcuts(self, skip=shortcuts_to_skip)
594 key_bindings = create_ipython_shortcuts(self, skip=shortcuts_to_skip)
580 for binding in shortcuts_to_add:
595 for binding in shortcuts_to_add:
581 add_binding(key_bindings, binding)
596 add_binding(key_bindings, binding)
582
597
583 return key_bindings
598 return key_bindings
584
599
585 prompt_includes_vi_mode = Bool(True,
600 prompt_includes_vi_mode = Bool(True,
586 help="Display the current vi mode (when using vi editing mode)."
601 help="Display the current vi mode (when using vi editing mode)."
587 ).tag(config=True)
602 ).tag(config=True)
588
603
589 prompt_line_number_format = Unicode(
604 prompt_line_number_format = Unicode(
590 "",
605 "",
591 help="The format for line numbering, will be passed `line` (int, 1 based)"
606 help="The format for line numbering, will be passed `line` (int, 1 based)"
592 " the current line number and `rel_line` the relative line number."
607 " the current line number and `rel_line` the relative line number."
593 " for example to display both you can use the following template string :"
608 " for example to display both you can use the following template string :"
594 " c.TerminalInteractiveShell.prompt_line_number_format='{line: 4d}/{rel_line:+03d} | '"
609 " c.TerminalInteractiveShell.prompt_line_number_format='{line: 4d}/{rel_line:+03d} | '"
595 " This will display the current line number, with leading space and a width of at least 4"
610 " This will display the current line number, with leading space and a width of at least 4"
596 " character, as well as the relative line number 0 padded and always with a + or - sign."
611 " character, as well as the relative line number 0 padded and always with a + or - sign."
597 " Note that when using Emacs mode the prompt of the first line may not update.",
612 " Note that when using Emacs mode the prompt of the first line may not update.",
598 ).tag(config=True)
613 ).tag(config=True)
599
614
600 @observe('term_title')
615 @observe('term_title')
601 def init_term_title(self, change=None):
616 def init_term_title(self, change=None):
602 # Enable or disable the terminal title.
617 # Enable or disable the terminal title.
603 if self.term_title and _is_tty:
618 if self.term_title and _is_tty:
604 toggle_set_term_title(True)
619 toggle_set_term_title(True)
605 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
620 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
606 else:
621 else:
607 toggle_set_term_title(False)
622 toggle_set_term_title(False)
608
623
609 def restore_term_title(self):
624 def restore_term_title(self):
610 if self.term_title and _is_tty:
625 if self.term_title and _is_tty:
611 restore_term_title()
626 restore_term_title()
612
627
613 def init_display_formatter(self):
628 def init_display_formatter(self):
614 super(TerminalInteractiveShell, self).init_display_formatter()
629 super(TerminalInteractiveShell, self).init_display_formatter()
615 # terminal only supports plain text
630 # terminal only supports plain text
616 self.display_formatter.active_types = ["text/plain"]
631 self.display_formatter.active_types = ["text/plain"]
617
632
618 def init_prompt_toolkit_cli(self):
633 def init_prompt_toolkit_cli(self):
619 if self.simple_prompt:
634 if self.simple_prompt:
620 # Fall back to plain non-interactive output for tests.
635 # Fall back to plain non-interactive output for tests.
621 # This is very limited.
636 # This is very limited.
622 def prompt():
637 def prompt():
623 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
638 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
624 lines = [input(prompt_text)]
639 lines = [input(prompt_text)]
625 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
640 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
626 while self.check_complete('\n'.join(lines))[0] == 'incomplete':
641 while self.check_complete('\n'.join(lines))[0] == 'incomplete':
627 lines.append( input(prompt_continuation) )
642 lines.append( input(prompt_continuation) )
628 return '\n'.join(lines)
643 return '\n'.join(lines)
629 self.prompt_for_code = prompt
644 self.prompt_for_code = prompt
630 return
645 return
631
646
632 # Set up keyboard shortcuts
647 # Set up keyboard shortcuts
633 key_bindings = self._merge_shortcuts(user_shortcuts=self.shortcuts)
648 key_bindings = self._merge_shortcuts(user_shortcuts=self.shortcuts)
634
649
635 # Pre-populate history from IPython's history database
650 # Pre-populate history from IPython's history database
636 history = PtkHistoryAdapter(self)
651 history = PtkHistoryAdapter(self)
637
652
638 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
653 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
639 self.style = DynamicStyle(lambda: self._style)
654 self.style = DynamicStyle(lambda: self._style)
640
655
641 editing_mode = getattr(EditingMode, self.editing_mode.upper())
656 editing_mode = getattr(EditingMode, self.editing_mode.upper())
642
657
643 self._use_asyncio_inputhook = False
658 self._use_asyncio_inputhook = False
644 self.pt_app = PromptSession(
659 self.pt_app = PromptSession(
645 auto_suggest=self.auto_suggest,
660 auto_suggest=self.auto_suggest,
646 editing_mode=editing_mode,
661 editing_mode=editing_mode,
647 key_bindings=key_bindings,
662 key_bindings=key_bindings,
648 history=history,
663 history=history,
649 completer=IPythonPTCompleter(shell=self),
664 completer=IPythonPTCompleter(shell=self),
650 enable_history_search=self.enable_history_search,
665 enable_history_search=self.enable_history_search,
651 style=self.style,
666 style=self.style,
652 include_default_pygments_style=False,
667 include_default_pygments_style=False,
653 mouse_support=self.mouse_support,
668 mouse_support=self.mouse_support,
654 enable_open_in_editor=self.extra_open_editor_shortcuts,
669 enable_open_in_editor=self.extra_open_editor_shortcuts,
655 color_depth=self.color_depth,
670 color_depth=self.color_depth,
656 tempfile_suffix=".py",
671 tempfile_suffix=".py",
657 **self._extra_prompt_options(),
672 **self._extra_prompt_options(),
658 )
673 )
659 if isinstance(self.auto_suggest, NavigableAutoSuggestFromHistory):
674 if isinstance(self.auto_suggest, NavigableAutoSuggestFromHistory):
660 self.auto_suggest.connect(self.pt_app)
675 self.auto_suggest.connect(self.pt_app)
661
676
662 def _make_style_from_name_or_cls(self, name_or_cls):
677 def _make_style_from_name_or_cls(self, name_or_cls):
663 """
678 """
664 Small wrapper that make an IPython compatible style from a style name
679 Small wrapper that make an IPython compatible style from a style name
665
680
666 We need that to add style for prompt ... etc.
681 We need that to add style for prompt ... etc.
667 """
682 """
668 style_overrides = {}
683 style_overrides = {}
669 if name_or_cls == 'legacy':
684 if name_or_cls == 'legacy':
670 legacy = self.colors.lower()
685 legacy = self.colors.lower()
671 if legacy == 'linux':
686 if legacy == 'linux':
672 style_cls = get_style_by_name('monokai')
687 style_cls = get_style_by_name('monokai')
673 style_overrides = _style_overrides_linux
688 style_overrides = _style_overrides_linux
674 elif legacy == 'lightbg':
689 elif legacy == 'lightbg':
675 style_overrides = _style_overrides_light_bg
690 style_overrides = _style_overrides_light_bg
676 style_cls = get_style_by_name('pastie')
691 style_cls = get_style_by_name('pastie')
677 elif legacy == 'neutral':
692 elif legacy == 'neutral':
678 # The default theme needs to be visible on both a dark background
693 # The default theme needs to be visible on both a dark background
679 # and a light background, because we can't tell what the terminal
694 # and a light background, because we can't tell what the terminal
680 # looks like. These tweaks to the default theme help with that.
695 # looks like. These tweaks to the default theme help with that.
681 style_cls = get_style_by_name('default')
696 style_cls = get_style_by_name('default')
682 style_overrides.update({
697 style_overrides.update({
683 Token.Number: '#ansigreen',
698 Token.Number: '#ansigreen',
684 Token.Operator: 'noinherit',
699 Token.Operator: 'noinherit',
685 Token.String: '#ansiyellow',
700 Token.String: '#ansiyellow',
686 Token.Name.Function: '#ansiblue',
701 Token.Name.Function: '#ansiblue',
687 Token.Name.Class: 'bold #ansiblue',
702 Token.Name.Class: 'bold #ansiblue',
688 Token.Name.Namespace: 'bold #ansiblue',
703 Token.Name.Namespace: 'bold #ansiblue',
689 Token.Name.Variable.Magic: '#ansiblue',
704 Token.Name.Variable.Magic: '#ansiblue',
690 Token.Prompt: '#ansigreen',
705 Token.Prompt: '#ansigreen',
691 Token.PromptNum: '#ansibrightgreen bold',
706 Token.PromptNum: '#ansibrightgreen bold',
692 Token.OutPrompt: '#ansired',
707 Token.OutPrompt: '#ansired',
693 Token.OutPromptNum: '#ansibrightred bold',
708 Token.OutPromptNum: '#ansibrightred bold',
694 })
709 })
695
710
696 # Hack: Due to limited color support on the Windows console
711 # Hack: Due to limited color support on the Windows console
697 # the prompt colors will be wrong without this
712 # the prompt colors will be wrong without this
698 if os.name == 'nt':
713 if os.name == 'nt':
699 style_overrides.update({
714 style_overrides.update({
700 Token.Prompt: '#ansidarkgreen',
715 Token.Prompt: '#ansidarkgreen',
701 Token.PromptNum: '#ansigreen bold',
716 Token.PromptNum: '#ansigreen bold',
702 Token.OutPrompt: '#ansidarkred',
717 Token.OutPrompt: '#ansidarkred',
703 Token.OutPromptNum: '#ansired bold',
718 Token.OutPromptNum: '#ansired bold',
704 })
719 })
705 elif legacy =='nocolor':
720 elif legacy =='nocolor':
706 style_cls=_NoStyle
721 style_cls=_NoStyle
707 style_overrides = {}
722 style_overrides = {}
708 else :
723 else :
709 raise ValueError('Got unknown colors: ', legacy)
724 raise ValueError('Got unknown colors: ', legacy)
710 else :
725 else :
711 if isinstance(name_or_cls, str):
726 if isinstance(name_or_cls, str):
712 style_cls = get_style_by_name(name_or_cls)
727 style_cls = get_style_by_name(name_or_cls)
713 else:
728 else:
714 style_cls = name_or_cls
729 style_cls = name_or_cls
715 style_overrides = {
730 style_overrides = {
716 Token.Prompt: '#ansigreen',
731 Token.Prompt: '#ansigreen',
717 Token.PromptNum: '#ansibrightgreen bold',
732 Token.PromptNum: '#ansibrightgreen bold',
718 Token.OutPrompt: '#ansired',
733 Token.OutPrompt: '#ansired',
719 Token.OutPromptNum: '#ansibrightred bold',
734 Token.OutPromptNum: '#ansibrightred bold',
720 }
735 }
721 style_overrides.update(self.highlighting_style_overrides)
736 style_overrides.update(self.highlighting_style_overrides)
722 style = merge_styles([
737 style = merge_styles([
723 style_from_pygments_cls(style_cls),
738 style_from_pygments_cls(style_cls),
724 style_from_pygments_dict(style_overrides),
739 style_from_pygments_dict(style_overrides),
725 ])
740 ])
726
741
727 return style
742 return style
728
743
729 @property
744 @property
730 def pt_complete_style(self):
745 def pt_complete_style(self):
731 return {
746 return {
732 'multicolumn': CompleteStyle.MULTI_COLUMN,
747 'multicolumn': CompleteStyle.MULTI_COLUMN,
733 'column': CompleteStyle.COLUMN,
748 'column': CompleteStyle.COLUMN,
734 'readlinelike': CompleteStyle.READLINE_LIKE,
749 'readlinelike': CompleteStyle.READLINE_LIKE,
735 }[self.display_completions]
750 }[self.display_completions]
736
751
737 @property
752 @property
738 def color_depth(self):
753 def color_depth(self):
739 return (ColorDepth.TRUE_COLOR if self.true_color else None)
754 return (ColorDepth.TRUE_COLOR if self.true_color else None)
740
755
741 def _extra_prompt_options(self):
756 def _extra_prompt_options(self):
742 """
757 """
743 Return the current layout option for the current Terminal InteractiveShell
758 Return the current layout option for the current Terminal InteractiveShell
744 """
759 """
745 def get_message():
760 def get_message():
746 return PygmentsTokens(self.prompts.in_prompt_tokens())
761 return PygmentsTokens(self.prompts.in_prompt_tokens())
747
762
748 if self.editing_mode == "emacs" and self.prompt_line_number_format == "":
763 if self.editing_mode == "emacs" and self.prompt_line_number_format == "":
749 # with emacs mode the prompt is (usually) static, so we call only
764 # with emacs mode the prompt is (usually) static, so we call only
750 # the function once. With VI mode it can toggle between [ins] and
765 # the function once. With VI mode it can toggle between [ins] and
751 # [nor] so we can't precompute.
766 # [nor] so we can't precompute.
752 # here I'm going to favor the default keybinding which almost
767 # here I'm going to favor the default keybinding which almost
753 # everybody uses to decrease CPU usage.
768 # everybody uses to decrease CPU usage.
754 # if we have issues with users with custom Prompts we can see how to
769 # if we have issues with users with custom Prompts we can see how to
755 # work around this.
770 # work around this.
756 get_message = get_message()
771 get_message = get_message()
757
772
758 options = {
773 options = {
759 "complete_in_thread": False,
774 "complete_in_thread": False,
760 "lexer": IPythonPTLexer(),
775 "lexer": IPythonPTLexer(),
761 "reserve_space_for_menu": self.space_for_menu,
776 "reserve_space_for_menu": self.space_for_menu,
762 "message": get_message,
777 "message": get_message,
763 "prompt_continuation": (
778 "prompt_continuation": (
764 lambda width, lineno, is_soft_wrap: PygmentsTokens(
779 lambda width, lineno, is_soft_wrap: PygmentsTokens(
765 self.prompts.continuation_prompt_tokens(width, lineno=lineno)
780 _backward_compat_continuation_prompt_tokens(
781 self.prompts.continuation_prompt_tokens, width, lineno=lineno
782 )
766 )
783 )
767 ),
784 ),
768 "multiline": True,
785 "multiline": True,
769 "complete_style": self.pt_complete_style,
786 "complete_style": self.pt_complete_style,
770 "input_processors": [
787 "input_processors": [
771 # Highlight matching brackets, but only when this setting is
788 # Highlight matching brackets, but only when this setting is
772 # enabled, and only when the DEFAULT_BUFFER has the focus.
789 # enabled, and only when the DEFAULT_BUFFER has the focus.
773 ConditionalProcessor(
790 ConditionalProcessor(
774 processor=HighlightMatchingBracketProcessor(chars="[](){}"),
791 processor=HighlightMatchingBracketProcessor(chars="[](){}"),
775 filter=HasFocus(DEFAULT_BUFFER)
792 filter=HasFocus(DEFAULT_BUFFER)
776 & ~IsDone()
793 & ~IsDone()
777 & Condition(lambda: self.highlight_matching_brackets),
794 & Condition(lambda: self.highlight_matching_brackets),
778 ),
795 ),
779 # Show auto-suggestion in lines other than the last line.
796 # Show auto-suggestion in lines other than the last line.
780 ConditionalProcessor(
797 ConditionalProcessor(
781 processor=AppendAutoSuggestionInAnyLine(),
798 processor=AppendAutoSuggestionInAnyLine(),
782 filter=HasFocus(DEFAULT_BUFFER)
799 filter=HasFocus(DEFAULT_BUFFER)
783 & ~IsDone()
800 & ~IsDone()
784 & Condition(
801 & Condition(
785 lambda: isinstance(
802 lambda: isinstance(
786 self.auto_suggest, NavigableAutoSuggestFromHistory
803 self.auto_suggest, NavigableAutoSuggestFromHistory
787 )
804 )
788 ),
805 ),
789 ),
806 ),
790 ],
807 ],
791 }
808 }
792 if not PTK3:
809 if not PTK3:
793 options['inputhook'] = self.inputhook
810 options['inputhook'] = self.inputhook
794
811
795 return options
812 return options
796
813
797 def prompt_for_code(self):
814 def prompt_for_code(self):
798 if self.rl_next_input:
815 if self.rl_next_input:
799 default = self.rl_next_input
816 default = self.rl_next_input
800 self.rl_next_input = None
817 self.rl_next_input = None
801 else:
818 else:
802 default = ''
819 default = ''
803
820
804 # In order to make sure that asyncio code written in the
821 # In order to make sure that asyncio code written in the
805 # interactive shell doesn't interfere with the prompt, we run the
822 # interactive shell doesn't interfere with the prompt, we run the
806 # prompt in a different event loop.
823 # prompt in a different event loop.
807 # If we don't do this, people could spawn coroutine with a
824 # If we don't do this, people could spawn coroutine with a
808 # while/true inside which will freeze the prompt.
825 # while/true inside which will freeze the prompt.
809
826
810 with patch_stdout(raw=True):
827 with patch_stdout(raw=True):
811 if self._use_asyncio_inputhook:
828 if self._use_asyncio_inputhook:
812 # When we integrate the asyncio event loop, run the UI in the
829 # When we integrate the asyncio event loop, run the UI in the
813 # same event loop as the rest of the code. don't use an actual
830 # same event loop as the rest of the code. don't use an actual
814 # input hook. (Asyncio is not made for nesting event loops.)
831 # input hook. (Asyncio is not made for nesting event loops.)
815 asyncio_loop = get_asyncio_loop()
832 asyncio_loop = get_asyncio_loop()
816 text = asyncio_loop.run_until_complete(
833 text = asyncio_loop.run_until_complete(
817 self.pt_app.prompt_async(
834 self.pt_app.prompt_async(
818 default=default, **self._extra_prompt_options()
835 default=default, **self._extra_prompt_options()
819 )
836 )
820 )
837 )
821 else:
838 else:
822 text = self.pt_app.prompt(
839 text = self.pt_app.prompt(
823 default=default,
840 default=default,
824 inputhook=self._inputhook,
841 inputhook=self._inputhook,
825 **self._extra_prompt_options(),
842 **self._extra_prompt_options(),
826 )
843 )
827
844
828 return text
845 return text
829
846
830 def enable_win_unicode_console(self):
847 def enable_win_unicode_console(self):
831 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
848 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
832 # console by default, so WUC shouldn't be needed.
849 # console by default, so WUC shouldn't be needed.
833 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
850 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
834 DeprecationWarning,
851 DeprecationWarning,
835 stacklevel=2)
852 stacklevel=2)
836
853
837 def init_io(self):
854 def init_io(self):
838 if sys.platform not in {'win32', 'cli'}:
855 if sys.platform not in {'win32', 'cli'}:
839 return
856 return
840
857
841 import colorama
858 import colorama
842 colorama.init()
859 colorama.init()
843
860
844 def init_magics(self):
861 def init_magics(self):
845 super(TerminalInteractiveShell, self).init_magics()
862 super(TerminalInteractiveShell, self).init_magics()
846 self.register_magics(TerminalMagics)
863 self.register_magics(TerminalMagics)
847
864
848 def init_alias(self):
865 def init_alias(self):
849 # The parent class defines aliases that can be safely used with any
866 # The parent class defines aliases that can be safely used with any
850 # frontend.
867 # frontend.
851 super(TerminalInteractiveShell, self).init_alias()
868 super(TerminalInteractiveShell, self).init_alias()
852
869
853 # Now define aliases that only make sense on the terminal, because they
870 # Now define aliases that only make sense on the terminal, because they
854 # need direct access to the console in a way that we can't emulate in
871 # need direct access to the console in a way that we can't emulate in
855 # GUI or web frontend
872 # GUI or web frontend
856 if os.name == 'posix':
873 if os.name == 'posix':
857 for cmd in ('clear', 'more', 'less', 'man'):
874 for cmd in ('clear', 'more', 'less', 'man'):
858 self.alias_manager.soft_define_alias(cmd, cmd)
875 self.alias_manager.soft_define_alias(cmd, cmd)
859
876
860 def __init__(self, *args, **kwargs) -> None:
877 def __init__(self, *args, **kwargs) -> None:
861 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
878 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
862 self._set_autosuggestions(self.autosuggestions_provider)
879 self._set_autosuggestions(self.autosuggestions_provider)
863 self.init_prompt_toolkit_cli()
880 self.init_prompt_toolkit_cli()
864 self.init_term_title()
881 self.init_term_title()
865 self.keep_running = True
882 self.keep_running = True
866 self._set_formatter(self.autoformatter)
883 self._set_formatter(self.autoformatter)
867
884
868 def ask_exit(self):
885 def ask_exit(self):
869 self.keep_running = False
886 self.keep_running = False
870
887
871 rl_next_input = None
888 rl_next_input = None
872
889
873 def interact(self):
890 def interact(self):
874 self.keep_running = True
891 self.keep_running = True
875 while self.keep_running:
892 while self.keep_running:
876 print(self.separate_in, end='')
893 print(self.separate_in, end='')
877
894
878 try:
895 try:
879 code = self.prompt_for_code()
896 code = self.prompt_for_code()
880 except EOFError:
897 except EOFError:
881 if (not self.confirm_exit) \
898 if (not self.confirm_exit) \
882 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
899 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
883 self.ask_exit()
900 self.ask_exit()
884
901
885 else:
902 else:
886 if code:
903 if code:
887 self.run_cell(code, store_history=True)
904 self.run_cell(code, store_history=True)
888
905
889 def mainloop(self):
906 def mainloop(self):
890 # An extra layer of protection in case someone mashing Ctrl-C breaks
907 # An extra layer of protection in case someone mashing Ctrl-C breaks
891 # out of our internal code.
908 # out of our internal code.
892 while True:
909 while True:
893 try:
910 try:
894 self.interact()
911 self.interact()
895 break
912 break
896 except KeyboardInterrupt as e:
913 except KeyboardInterrupt as e:
897 print("\n%s escaped interact()\n" % type(e).__name__)
914 print("\n%s escaped interact()\n" % type(e).__name__)
898 finally:
915 finally:
899 # An interrupt during the eventloop will mess up the
916 # An interrupt during the eventloop will mess up the
900 # internal state of the prompt_toolkit library.
917 # internal state of the prompt_toolkit library.
901 # Stopping the eventloop fixes this, see
918 # Stopping the eventloop fixes this, see
902 # https://github.com/ipython/ipython/pull/9867
919 # https://github.com/ipython/ipython/pull/9867
903 if hasattr(self, '_eventloop'):
920 if hasattr(self, '_eventloop'):
904 self._eventloop.stop()
921 self._eventloop.stop()
905
922
906 self.restore_term_title()
923 self.restore_term_title()
907
924
908 # try to call some at-exit operation optimistically as some things can't
925 # try to call some at-exit operation optimistically as some things can't
909 # be done during interpreter shutdown. this is technically inaccurate as
926 # be done during interpreter shutdown. this is technically inaccurate as
910 # this make mainlool not re-callable, but that should be a rare if not
927 # this make mainlool not re-callable, but that should be a rare if not
911 # in existent use case.
928 # in existent use case.
912
929
913 self._atexit_once()
930 self._atexit_once()
914
931
915 _inputhook = None
932 _inputhook = None
916 def inputhook(self, context):
933 def inputhook(self, context):
917 if self._inputhook is not None:
934 if self._inputhook is not None:
918 self._inputhook(context)
935 self._inputhook(context)
919
936
920 active_eventloop: Optional[str] = None
937 active_eventloop: Optional[str] = None
921
938
922 def enable_gui(self, gui: Optional[str] = None) -> None:
939 def enable_gui(self, gui: Optional[str] = None) -> None:
923 if self.simple_prompt is True and gui is not None:
940 if self.simple_prompt is True and gui is not None:
924 print(
941 print(
925 f'Cannot install event loop hook for "{gui}" when running with `--simple-prompt`.'
942 f'Cannot install event loop hook for "{gui}" when running with `--simple-prompt`.'
926 )
943 )
927 print(
944 print(
928 "NOTE: Tk is supported natively; use Tk apps and Tk backends with `--simple-prompt`."
945 "NOTE: Tk is supported natively; use Tk apps and Tk backends with `--simple-prompt`."
929 )
946 )
930 return
947 return
931
948
932 if self._inputhook is None and gui is None:
949 if self._inputhook is None and gui is None:
933 print("No event loop hook running.")
950 print("No event loop hook running.")
934 return
951 return
935
952
936 if self._inputhook is not None and gui is not None:
953 if self._inputhook is not None and gui is not None:
937 newev, newinhook = get_inputhook_name_and_func(gui)
954 newev, newinhook = get_inputhook_name_and_func(gui)
938 if self._inputhook == newinhook:
955 if self._inputhook == newinhook:
939 # same inputhook, do nothing
956 # same inputhook, do nothing
940 self.log.info(
957 self.log.info(
941 f"Shell is already running the {self.active_eventloop} eventloop. Doing nothing"
958 f"Shell is already running the {self.active_eventloop} eventloop. Doing nothing"
942 )
959 )
943 return
960 return
944 self.log.warning(
961 self.log.warning(
945 f"Shell is already running a different gui event loop for {self.active_eventloop}. "
962 f"Shell is already running a different gui event loop for {self.active_eventloop}. "
946 "Call with no arguments to disable the current loop."
963 "Call with no arguments to disable the current loop."
947 )
964 )
948 return
965 return
949 if self._inputhook is not None and gui is None:
966 if self._inputhook is not None and gui is None:
950 self.active_eventloop = self._inputhook = None
967 self.active_eventloop = self._inputhook = None
951
968
952 if gui and (gui not in {"inline", "webagg"}):
969 if gui and (gui not in {"inline", "webagg"}):
953 # This hook runs with each cycle of the `prompt_toolkit`'s event loop.
970 # This hook runs with each cycle of the `prompt_toolkit`'s event loop.
954 self.active_eventloop, self._inputhook = get_inputhook_name_and_func(gui)
971 self.active_eventloop, self._inputhook = get_inputhook_name_and_func(gui)
955 else:
972 else:
956 self.active_eventloop = self._inputhook = None
973 self.active_eventloop = self._inputhook = None
957
974
958 self._use_asyncio_inputhook = gui == "asyncio"
975 self._use_asyncio_inputhook = gui == "asyncio"
959
976
960 # Run !system commands directly, not through pipes, so terminal programs
977 # Run !system commands directly, not through pipes, so terminal programs
961 # work correctly.
978 # work correctly.
962 system = InteractiveShell.system_raw
979 system = InteractiveShell.system_raw
963
980
964 def auto_rewrite_input(self, cmd):
981 def auto_rewrite_input(self, cmd):
965 """Overridden from the parent class to use fancy rewriting prompt"""
982 """Overridden from the parent class to use fancy rewriting prompt"""
966 if not self.show_rewritten_input:
983 if not self.show_rewritten_input:
967 return
984 return
968
985
969 tokens = self.prompts.rewrite_prompt_tokens()
986 tokens = self.prompts.rewrite_prompt_tokens()
970 if self.pt_app:
987 if self.pt_app:
971 print_formatted_text(PygmentsTokens(tokens), end='',
988 print_formatted_text(PygmentsTokens(tokens), end='',
972 style=self.pt_app.app.style)
989 style=self.pt_app.app.style)
973 print(cmd)
990 print(cmd)
974 else:
991 else:
975 prompt = ''.join(s for t, s in tokens)
992 prompt = ''.join(s for t, s in tokens)
976 print(prompt, cmd, sep='')
993 print(prompt, cmd, sep='')
977
994
978 _prompts_before = None
995 _prompts_before = None
979 def switch_doctest_mode(self, mode):
996 def switch_doctest_mode(self, mode):
980 """Switch prompts to classic for %doctest_mode"""
997 """Switch prompts to classic for %doctest_mode"""
981 if mode:
998 if mode:
982 self._prompts_before = self.prompts
999 self._prompts_before = self.prompts
983 self.prompts = ClassicPrompts(self)
1000 self.prompts = ClassicPrompts(self)
984 elif self._prompts_before:
1001 elif self._prompts_before:
985 self.prompts = self._prompts_before
1002 self.prompts = self._prompts_before
986 self._prompts_before = None
1003 self._prompts_before = None
987 # self._update_layout()
1004 # self._update_layout()
988
1005
989
1006
990 InteractiveShellABC.register(TerminalInteractiveShell)
1007 InteractiveShellABC.register(TerminalInteractiveShell)
991
1008
992 if __name__ == '__main__':
1009 if __name__ == '__main__':
993 TerminalInteractiveShell.instance().interact()
1010 TerminalInteractiveShell.instance().interact()
@@ -1,323 +1,321 b''
1 =======================
1 =======================
2 Specific config details
2 Specific config details
3 =======================
3 =======================
4
4
5 .. _custom_prompts:
5 .. _custom_prompts:
6
6
7 Custom Prompts
7 Custom Prompts
8 ==============
8 ==============
9
9
10 .. versionchanged:: 5.0
10 .. versionchanged:: 5.0
11
11
12 From IPython 5, prompts are produced as a list of Pygments tokens, which are
12 From IPython 5, prompts are produced as a list of Pygments tokens, which are
13 tuples of (token_type, text). You can customise prompts by writing a method
13 tuples of (token_type, text). You can customise prompts by writing a method
14 which generates a list of tokens.
14 which generates a list of tokens.
15
15
16 There are four kinds of prompt:
16 There are four kinds of prompt:
17
17
18 * The **in** prompt is shown before the first line of input
18 * The **in** prompt is shown before the first line of input
19 (default like ``In [1]:``).
19 (default like ``In [1]:``).
20 * The **continuation** prompt is shown before further lines of input
20 * The **continuation** prompt is shown before further lines of input
21 (default like ``...:``).
21 (default like ``...:``).
22 * The **rewrite** prompt is shown to highlight how special syntax has been
22 * The **rewrite** prompt is shown to highlight how special syntax has been
23 interpreted (default like ``----->``).
23 interpreted (default like ``----->``).
24 * The **out** prompt is shown before the result from evaluating the input
24 * The **out** prompt is shown before the result from evaluating the input
25 (default like ``Out[1]:``).
25 (default like ``Out[1]:``).
26
26
27 Custom prompts are supplied together as a class. If you want to customise only
27 Custom prompts are supplied together as a class. If you want to customise only
28 some of the prompts, inherit from :class:`IPython.terminal.prompts.Prompts`,
28 some of the prompts, inherit from :class:`IPython.terminal.prompts.Prompts`,
29 which defines the defaults. The required interface is like this:
29 which defines the defaults. The required interface is like this:
30
30
31 .. class:: MyPrompts(shell)
31 .. class:: MyPrompts(shell)
32
32
33 Prompt style definition. *shell* is a reference to the
33 Prompt style definition. *shell* is a reference to the
34 :class:`~.TerminalInteractiveShell` instance.
34 :class:`~.TerminalInteractiveShell` instance.
35
35
36 .. method:: in_prompt_tokens(cli=None)
36 .. method:: in_prompt_tokens()
37 continuation_prompt_tokens(self, cli=None, width=None)
37 continuation_prompt_tokens(self, width=None)
38 rewrite_prompt_tokens()
38 rewrite_prompt_tokens()
39 out_prompt_tokens()
39 out_prompt_tokens()
40
40
41 Return the respective prompts as lists of ``(token_type, text)`` tuples.
41 Return the respective prompts as lists of ``(token_type, text)`` tuples.
42
42
43 For continuation prompts, *width* is an integer representing the width of
43 For continuation prompts, *width* is an integer representing the width of
44 the prompt area in terminal columns.
44 the prompt area in terminal columns.
45
45
46 *cli*, where used, is the prompt_toolkit ``CommandLineInterface`` instance.
47 This is mainly for compatibility with the API prompt_toolkit expects.
48
46
49 Here is an example Prompt class that will show the current working directory
47 Here is an example Prompt class that will show the current working directory
50 in the input prompt:
48 in the input prompt:
51
49
52 .. code-block:: python
50 .. code-block:: python
53
51
54 from IPython.terminal.prompts import Prompts, Token
52 from IPython.terminal.prompts import Prompts, Token
55 import os
53 import os
56
54
57 class MyPrompt(Prompts):
55 class MyPrompt(Prompts):
58 def in_prompt_tokens(self, cli=None):
56 def in_prompt_tokens(self):
59 return [(Token, os.getcwd()),
57 return [(Token, os.getcwd()),
60 (Token.Prompt, ' >>>')]
58 (Token.Prompt, ' >>>')]
61
59
62 To set the new prompt, assign it to the ``prompts`` attribute of the IPython
60 To set the new prompt, assign it to the ``prompts`` attribute of the IPython
63 shell:
61 shell:
64
62
65 .. code-block:: python
63 .. code-block:: python
66
64
67 In [2]: ip = get_ipython()
65 In [2]: ip = get_ipython()
68 ...: ip.prompts = MyPrompt(ip)
66 ...: ip.prompts = MyPrompt(ip)
69
67
70 /home/bob >>> # it works
68 /home/bob >>> # it works
71
69
72 See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write
70 See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write
73 extensions to customise prompts.
71 extensions to customise prompts.
74
72
75 Inside IPython or in a startup script, you can use a custom prompts class
73 Inside IPython or in a startup script, you can use a custom prompts class
76 by setting ``get_ipython().prompts`` to an *instance* of the class.
74 by setting ``get_ipython().prompts`` to an *instance* of the class.
77 In configuration, ``TerminalInteractiveShell.prompts_class`` may be set to
75 In configuration, ``TerminalInteractiveShell.prompts_class`` may be set to
78 either the class object, or a string of its full importable name.
76 either the class object, or a string of its full importable name.
79
77
80 To include invisible terminal control sequences in a prompt, use
78 To include invisible terminal control sequences in a prompt, use
81 ``Token.ZeroWidthEscape`` as the token type. Tokens with this type are ignored
79 ``Token.ZeroWidthEscape`` as the token type. Tokens with this type are ignored
82 when calculating the width.
80 when calculating the width.
83
81
84 Colours in the prompt are determined by the token types and the highlighting
82 Colours in the prompt are determined by the token types and the highlighting
85 style; see below for more details. The tokens used in the default prompts are
83 style; see below for more details. The tokens used in the default prompts are
86 ``Prompt``, ``PromptNum``, ``OutPrompt`` and ``OutPromptNum``.
84 ``Prompt``, ``PromptNum``, ``OutPrompt`` and ``OutPromptNum``.
87
85
88 .. _termcolour:
86 .. _termcolour:
89
87
90 Terminal Colors
88 Terminal Colors
91 ===============
89 ===============
92
90
93 .. versionchanged:: 5.0
91 .. versionchanged:: 5.0
94
92
95 There are two main configuration options controlling colours.
93 There are two main configuration options controlling colours.
96
94
97 ``InteractiveShell.colors`` sets the colour of tracebacks and object info (the
95 ``InteractiveShell.colors`` sets the colour of tracebacks and object info (the
98 output from e.g. ``zip?``). It may also affect other things if the option below
96 output from e.g. ``zip?``). It may also affect other things if the option below
99 is set to ``'legacy'``. It has four case-insensitive values:
97 is set to ``'legacy'``. It has four case-insensitive values:
100 ``'nocolor', 'neutral', 'linux', 'lightbg'``. The default is *neutral*, which
98 ``'nocolor', 'neutral', 'linux', 'lightbg'``. The default is *neutral*, which
101 should be legible on either dark or light terminal backgrounds. *linux* is
99 should be legible on either dark or light terminal backgrounds. *linux* is
102 optimised for dark backgrounds and *lightbg* for light ones.
100 optimised for dark backgrounds and *lightbg* for light ones.
103
101
104 ``TerminalInteractiveShell.highlighting_style`` determines prompt colours and
102 ``TerminalInteractiveShell.highlighting_style`` determines prompt colours and
105 syntax highlighting. It takes the name (as a string) or class (as a subclass of
103 syntax highlighting. It takes the name (as a string) or class (as a subclass of
106 ``pygments.style.Style``) of a Pygments style, or the special value ``'legacy'``
104 ``pygments.style.Style``) of a Pygments style, or the special value ``'legacy'``
107 to pick a style in accordance with ``InteractiveShell.colors``.
105 to pick a style in accordance with ``InteractiveShell.colors``.
108
106
109 You can see the Pygments styles available on your system by running::
107 You can see the Pygments styles available on your system by running::
110
108
111 from pygments.styles import get_all_styles
109 from pygments.styles import get_all_styles
112 list(get_all_styles())
110 list(get_all_styles())
113
111
114 Additionally, ``TerminalInteractiveShell.highlighting_style_overrides`` can override
112 Additionally, ``TerminalInteractiveShell.highlighting_style_overrides`` can override
115 specific styles in the highlighting. It should be a dictionary mapping Pygments
113 specific styles in the highlighting. It should be a dictionary mapping Pygments
116 token types to strings defining the style. See `Pygments' documentation
114 token types to strings defining the style. See `Pygments' documentation
117 <http://pygments.org/docs/styles/#creating-own-styles>`__ for the language used
115 <http://pygments.org/docs/styles/#creating-own-styles>`__ for the language used
118 to define styles.
116 to define styles.
119
117
120 Colors in the pager
118 Colors in the pager
121 -------------------
119 -------------------
122
120
123 On some systems, the default pager has problems with ANSI colour codes.
121 On some systems, the default pager has problems with ANSI colour codes.
124 To configure your default pager to allow these:
122 To configure your default pager to allow these:
125
123
126 1. Set the environment PAGER variable to ``less``.
124 1. Set the environment PAGER variable to ``less``.
127 2. Set the environment LESS variable to ``-r`` (plus any other options
125 2. Set the environment LESS variable to ``-r`` (plus any other options
128 you always want to pass to less by default). This tells less to
126 you always want to pass to less by default). This tells less to
129 properly interpret control sequences, which is how color
127 properly interpret control sequences, which is how color
130 information is given to your terminal.
128 information is given to your terminal.
131
129
132 .. _editors:
130 .. _editors:
133
131
134 Editor configuration
132 Editor configuration
135 ====================
133 ====================
136
134
137 IPython can integrate with text editors in a number of different ways:
135 IPython can integrate with text editors in a number of different ways:
138
136
139 * Editors (such as `(X)Emacs`_, vim_ and TextMate_) can
137 * Editors (such as `(X)Emacs`_, vim_ and TextMate_) can
140 send code to IPython for execution.
138 send code to IPython for execution.
141
139
142 * IPython's ``%edit`` magic command can open an editor of choice to edit
140 * IPython's ``%edit`` magic command can open an editor of choice to edit
143 a code block.
141 a code block.
144
142
145 The %edit command (and its alias %ed) will invoke the editor set in your
143 The %edit command (and its alias %ed) will invoke the editor set in your
146 environment as :envvar:`EDITOR`. If this variable is not set, it will default
144 environment as :envvar:`EDITOR`. If this variable is not set, it will default
147 to vi under Linux/Unix and to notepad under Windows. You may want to set this
145 to vi under Linux/Unix and to notepad under Windows. You may want to set this
148 variable properly and to a lightweight editor which doesn't take too long to
146 variable properly and to a lightweight editor which doesn't take too long to
149 start (that is, something other than a new instance of Emacs). This way you
147 start (that is, something other than a new instance of Emacs). This way you
150 can edit multi-line code quickly and with the power of a real editor right
148 can edit multi-line code quickly and with the power of a real editor right
151 inside IPython.
149 inside IPython.
152
150
153 You can also control the editor by setting :attr:`TerminalInteractiveShell.editor`
151 You can also control the editor by setting :attr:`TerminalInteractiveShell.editor`
154 in :file:`ipython_config.py`.
152 in :file:`ipython_config.py`.
155
153
156 Vim
154 Vim
157 ---
155 ---
158
156
159 Paul Ivanov's `vim-ipython <https://github.com/ivanov/vim-ipython>`_ provides
157 Paul Ivanov's `vim-ipython <https://github.com/ivanov/vim-ipython>`_ provides
160 powerful IPython integration for vim.
158 powerful IPython integration for vim.
161
159
162 .. _emacs:
160 .. _emacs:
163
161
164 (X)Emacs
162 (X)Emacs
165 --------
163 --------
166
164
167 If you are a dedicated Emacs user, and want to use Emacs when IPython's
165 If you are a dedicated Emacs user, and want to use Emacs when IPython's
168 ``%edit`` magic command is called you should set up the Emacs server so that
166 ``%edit`` magic command is called you should set up the Emacs server so that
169 new requests are handled by the original process. This means that almost no
167 new requests are handled by the original process. This means that almost no
170 time is spent in handling the request (assuming an Emacs process is already
168 time is spent in handling the request (assuming an Emacs process is already
171 running). For this to work, you need to set your EDITOR environment variable
169 running). For this to work, you need to set your EDITOR environment variable
172 to 'emacsclient'. The code below, supplied by Francois Pinard, can then be
170 to 'emacsclient'. The code below, supplied by Francois Pinard, can then be
173 used in your :file:`.emacs` file to enable the server:
171 used in your :file:`.emacs` file to enable the server:
174
172
175 .. code-block:: common-lisp
173 .. code-block:: common-lisp
176
174
177 (defvar server-buffer-clients)
175 (defvar server-buffer-clients)
178 (when (and (fboundp 'server-start) (string-equal (getenv "TERM") 'xterm))
176 (when (and (fboundp 'server-start) (string-equal (getenv "TERM") 'xterm))
179 (server-start)
177 (server-start)
180 (defun fp-kill-server-with-buffer-routine ()
178 (defun fp-kill-server-with-buffer-routine ()
181 (and server-buffer-clients (server-done)))
179 (and server-buffer-clients (server-done)))
182 (add-hook 'kill-buffer-hook 'fp-kill-server-with-buffer-routine))
180 (add-hook 'kill-buffer-hook 'fp-kill-server-with-buffer-routine))
183
181
184 Thanks to the work of Alexander Schmolck and Prabhu Ramachandran,
182 Thanks to the work of Alexander Schmolck and Prabhu Ramachandran,
185 currently (X)Emacs and IPython get along very well in other ways.
183 currently (X)Emacs and IPython get along very well in other ways.
186
184
187 With (X)EMacs >= 24, You can enable IPython in python-mode with:
185 With (X)EMacs >= 24, You can enable IPython in python-mode with:
188
186
189 .. code-block:: common-lisp
187 .. code-block:: common-lisp
190
188
191 (require 'python)
189 (require 'python)
192 (setq python-shell-interpreter "ipython")
190 (setq python-shell-interpreter "ipython")
193
191
194 .. _`(X)Emacs`: http://www.gnu.org/software/emacs/
192 .. _`(X)Emacs`: http://www.gnu.org/software/emacs/
195 .. _TextMate: http://macromates.com/
193 .. _TextMate: http://macromates.com/
196 .. _vim: http://www.vim.org/
194 .. _vim: http://www.vim.org/
197
195
198 .. _custom_keyboard_shortcuts:
196 .. _custom_keyboard_shortcuts:
199
197
200 Keyboard Shortcuts
198 Keyboard Shortcuts
201 ==================
199 ==================
202
200
203 .. versionadded:: 8.11
201 .. versionadded:: 8.11
204
202
205 You can modify, disable or modify keyboard shortcuts for IPython Terminal using
203 You can modify, disable or modify keyboard shortcuts for IPython Terminal using
206 :std:configtrait:`TerminalInteractiveShell.shortcuts` traitlet.
204 :std:configtrait:`TerminalInteractiveShell.shortcuts` traitlet.
207
205
208 The list of shortcuts is available in the Configuring IPython :ref:`terminal-shortcuts-list` section.
206 The list of shortcuts is available in the Configuring IPython :ref:`terminal-shortcuts-list` section.
209
207
210 Advanced configuration
208 Advanced configuration
211 ----------------------
209 ----------------------
212
210
213 .. versionchanged:: 5.0
211 .. versionchanged:: 5.0
214
212
215 Creating custom commands requires adding custom code to a
213 Creating custom commands requires adding custom code to a
216 :ref:`startup file <startup_files>`::
214 :ref:`startup file <startup_files>`::
217
215
218 from IPython import get_ipython
216 from IPython import get_ipython
219 from prompt_toolkit.enums import DEFAULT_BUFFER
217 from prompt_toolkit.enums import DEFAULT_BUFFER
220 from prompt_toolkit.keys import Keys
218 from prompt_toolkit.keys import Keys
221 from prompt_toolkit.filters import HasFocus, HasSelection, ViInsertMode, EmacsInsertMode
219 from prompt_toolkit.filters import HasFocus, HasSelection, ViInsertMode, EmacsInsertMode
222
220
223 ip = get_ipython()
221 ip = get_ipython()
224 insert_mode = ViInsertMode() | EmacsInsertMode()
222 insert_mode = ViInsertMode() | EmacsInsertMode()
225
223
226 def insert_unexpected(event):
224 def insert_unexpected(event):
227 buf = event.current_buffer
225 buf = event.current_buffer
228 buf.insert_text('The Spanish Inquisition')
226 buf.insert_text('The Spanish Inquisition')
229 # Register the shortcut if IPython is using prompt_toolkit
227 # Register the shortcut if IPython is using prompt_toolkit
230 if getattr(ip, 'pt_app', None):
228 if getattr(ip, 'pt_app', None):
231 registry = ip.pt_app.key_bindings
229 registry = ip.pt_app.key_bindings
232 registry.add_binding(Keys.ControlN,
230 registry.add_binding(Keys.ControlN,
233 filter=(HasFocus(DEFAULT_BUFFER)
231 filter=(HasFocus(DEFAULT_BUFFER)
234 & ~HasSelection()
232 & ~HasSelection()
235 & insert_mode))(insert_unexpected)
233 & insert_mode))(insert_unexpected)
236
234
237
235
238 Here is a second example that bind the key sequence ``j``, ``k`` to switch to
236 Here is a second example that bind the key sequence ``j``, ``k`` to switch to
239 VI input mode to ``Normal`` when in insert mode::
237 VI input mode to ``Normal`` when in insert mode::
240
238
241 from IPython import get_ipython
239 from IPython import get_ipython
242 from prompt_toolkit.enums import DEFAULT_BUFFER
240 from prompt_toolkit.enums import DEFAULT_BUFFER
243 from prompt_toolkit.filters import HasFocus, ViInsertMode
241 from prompt_toolkit.filters import HasFocus, ViInsertMode
244 from prompt_toolkit.key_binding.vi_state import InputMode
242 from prompt_toolkit.key_binding.vi_state import InputMode
245
243
246 ip = get_ipython()
244 ip = get_ipython()
247
245
248 def switch_to_navigation_mode(event):
246 def switch_to_navigation_mode(event):
249 vi_state = event.cli.vi_state
247 vi_state = event.cli.vi_state
250 vi_state.input_mode = InputMode.NAVIGATION
248 vi_state.input_mode = InputMode.NAVIGATION
251
249
252 if getattr(ip, 'pt_app', None):
250 if getattr(ip, 'pt_app', None):
253 registry = ip.pt_app.key_bindings
251 registry = ip.pt_app.key_bindings
254 registry.add_binding(u'j',u'k',
252 registry.add_binding(u'j',u'k',
255 filter=(HasFocus(DEFAULT_BUFFER)
253 filter=(HasFocus(DEFAULT_BUFFER)
256 & ViInsertMode()))(switch_to_navigation_mode)
254 & ViInsertMode()))(switch_to_navigation_mode)
257
255
258 For more information on filters and what you can do with the ``event`` object,
256 For more information on filters and what you can do with the ``event`` object,
259 `see the prompt_toolkit docs
257 `see the prompt_toolkit docs
260 <https://python-prompt-toolkit.readthedocs.io/en/latest/pages/asking_for_input.html#adding-custom-key-bindings>`__.
258 <https://python-prompt-toolkit.readthedocs.io/en/latest/pages/asking_for_input.html#adding-custom-key-bindings>`__.
261
259
262
260
263 Enter to execute
261 Enter to execute
264 ----------------
262 ----------------
265
263
266 In the Terminal IPython shell – which by default uses the ``prompt_toolkit``
264 In the Terminal IPython shell – which by default uses the ``prompt_toolkit``
267 interface, the semantic meaning of pressing the :kbd:`Enter` key can be
265 interface, the semantic meaning of pressing the :kbd:`Enter` key can be
268 ambiguous. In some case :kbd:`Enter` should execute code, and in others it
266 ambiguous. In some case :kbd:`Enter` should execute code, and in others it
269 should add a new line. IPython uses heuristics to decide whether to execute or
267 should add a new line. IPython uses heuristics to decide whether to execute or
270 insert a new line at cursor position. For example, if we detect that the current
268 insert a new line at cursor position. For example, if we detect that the current
271 code is not valid Python, then the user is likely editing code and the right
269 code is not valid Python, then the user is likely editing code and the right
272 behavior is to likely to insert a new line. If the current code is a simple
270 behavior is to likely to insert a new line. If the current code is a simple
273 statement like `ord('*')`, then the right behavior is likely to execute. Though
271 statement like `ord('*')`, then the right behavior is likely to execute. Though
274 the exact desired semantics often varies from users to users.
272 the exact desired semantics often varies from users to users.
275
273
276 As the exact behavior of :kbd:`Enter` is ambiguous, it has been special cased
274 As the exact behavior of :kbd:`Enter` is ambiguous, it has been special cased
277 to allow users to completely configure the behavior they like. Hence you can
275 to allow users to completely configure the behavior they like. Hence you can
278 have enter always execute code. If you prefer fancier behavior, you need to get
276 have enter always execute code. If you prefer fancier behavior, you need to get
279 your hands dirty and read the ``prompt_toolkit`` and IPython documentation
277 your hands dirty and read the ``prompt_toolkit`` and IPython documentation
280 though. See :ghpull:`10500`, set the
278 though. See :ghpull:`10500`, set the
281 ``c.TerminalInteractiveShell.handle_return`` option and get inspiration from the
279 ``c.TerminalInteractiveShell.handle_return`` option and get inspiration from the
282 following example that only auto-executes the input if it begins with a bang or
280 following example that only auto-executes the input if it begins with a bang or
283 a modulo character (``!`` or ``%``). To use the following code, add it to your
281 a modulo character (``!`` or ``%``). To use the following code, add it to your
284 IPython configuration::
282 IPython configuration::
285
283
286 def custom_return(shell):
284 def custom_return(shell):
287
285
288 """This function is required by the API. It takes a reference to
286 """This function is required by the API. It takes a reference to
289 the shell, which is the same thing `get_ipython()` evaluates to.
287 the shell, which is the same thing `get_ipython()` evaluates to.
290 This function must return a function that handles each keypress
288 This function must return a function that handles each keypress
291 event. That function, named `handle` here, references `shell`
289 event. That function, named `handle` here, references `shell`
292 by closure."""
290 by closure."""
293
291
294 def handle(event):
292 def handle(event):
295
293
296 """This function is called each time `Enter` is pressed,
294 """This function is called each time `Enter` is pressed,
297 and takes a reference to a Prompt Toolkit event object.
295 and takes a reference to a Prompt Toolkit event object.
298 If the current input starts with a bang or modulo, then
296 If the current input starts with a bang or modulo, then
299 the input is executed, otherwise a newline is entered,
297 the input is executed, otherwise a newline is entered,
300 followed by any spaces needed to auto-indent."""
298 followed by any spaces needed to auto-indent."""
301
299
302 # set up a few handy references to nested items...
300 # set up a few handy references to nested items...
303
301
304 buffer = event.current_buffer
302 buffer = event.current_buffer
305 document = buffer.document
303 document = buffer.document
306 text = document.text
304 text = document.text
307
305
308 if text.startswith('!') or text.startswith('%'): # execute the input...
306 if text.startswith('!') or text.startswith('%'): # execute the input...
309
307
310 buffer.accept_action.validate_and_handle(event.cli, buffer)
308 buffer.accept_action.validate_and_handle(event.cli, buffer)
311
309
312 else: # insert a newline with auto-indentation...
310 else: # insert a newline with auto-indentation...
313
311
314 if document.line_count > 1: text = text[:document.cursor_position]
312 if document.line_count > 1: text = text[:document.cursor_position]
315 indent = shell.check_complete(text)[1]
313 indent = shell.check_complete(text)[1]
316 buffer.insert_text('\n' + indent)
314 buffer.insert_text('\n' + indent)
317
315
318 # if you just wanted a plain newline without any indentation, you
316 # if you just wanted a plain newline without any indentation, you
319 # could use `buffer.insert_text('\n')` instead of the lines above
317 # could use `buffer.insert_text('\n')` instead of the lines above
320
318
321 return handle
319 return handle
322
320
323 c.TerminalInteractiveShell.handle_return = custom_return
321 c.TerminalInteractiveShell.handle_return = custom_return
@@ -1,145 +1,145 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """An example of how to embed an IPython shell into a running program.
2 """An example of how to embed an IPython shell into a running program.
3
3
4 Please see the documentation in the IPython.Shell module for more details.
4 Please see the documentation in the IPython.Shell module for more details.
5
5
6 The accompanying file embed_class_short.py has quick code fragments for
6 The accompanying file embed_class_short.py has quick code fragments for
7 embedding which you can cut and paste in your code once you understand how
7 embedding which you can cut and paste in your code once you understand how
8 things work.
8 things work.
9
9
10 The code in this file is deliberately extra-verbose, meant for learning."""
10 The code in this file is deliberately extra-verbose, meant for learning."""
11
11
12 # The basics to get you going:
12 # The basics to get you going:
13
13
14 # IPython injects get_ipython into builtins, so you can know if you have nested
14 # IPython injects get_ipython into builtins, so you can know if you have nested
15 # copies running.
15 # copies running.
16
16
17 # Try running this code both at the command line and from inside IPython (with
17 # Try running this code both at the command line and from inside IPython (with
18 # %run example-embed.py)
18 # %run example-embed.py)
19
19
20 from IPython.terminal.prompts import Prompts, Token
20 from IPython.terminal.prompts import Prompts, Token
21 from traitlets.config.loader import Config
21
22
22 class CustomPrompt(Prompts):
23 class CustomPrompt(Prompts):
23
24
24 def in_prompt_tokens(self, cli=None):
25 def in_prompt_tokens(self):
25
26
26 return [
27 return [
27 (Token.Prompt, 'In <'),
28 (Token.Prompt, 'In <'),
28 (Token.PromptNum, str(self.shell.execution_count)),
29 (Token.PromptNum, str(self.shell.execution_count)),
29 (Token.Prompt, '>: '),
30 (Token.Prompt, '>: '),
30 ]
31 ]
31
32
32 def out_prompt_tokens(self):
33 def out_prompt_tokens(self):
33 return [
34 return [
34 (Token.OutPrompt, 'Out<'),
35 (Token.OutPrompt, 'Out<'),
35 (Token.OutPromptNum, str(self.shell.execution_count)),
36 (Token.OutPromptNum, str(self.shell.execution_count)),
36 (Token.OutPrompt, '>: '),
37 (Token.OutPrompt, '>: '),
37 ]
38 ]
38
39
39
40
40 from traitlets.config.loader import Config
41 try:
41 try:
42 get_ipython
42 get_ipython
43 except NameError:
43 except NameError:
44 nested = 0
44 nested = 0
45 cfg = Config()
45 cfg = Config()
46 cfg.TerminalInteractiveShell.prompts_class=CustomPrompt
46 cfg.TerminalInteractiveShell.prompts_class=CustomPrompt
47 else:
47 else:
48 print("Running nested copies of IPython.")
48 print("Running nested copies of IPython.")
49 print("The prompts for the nested copy have been modified")
49 print("The prompts for the nested copy have been modified")
50 cfg = Config()
50 cfg = Config()
51 nested = 1
51 nested = 1
52
52
53 # First import the embeddable shell class
53 # First import the embeddable shell class
54 from IPython.terminal.embed import InteractiveShellEmbed
54 from IPython.terminal.embed import InteractiveShellEmbed
55
55
56 # Now create an instance of the embeddable shell. The first argument is a
56 # Now create an instance of the embeddable shell. The first argument is a
57 # string with options exactly as you would type them if you were starting
57 # string with options exactly as you would type them if you were starting
58 # IPython at the system command line. Any parameters you want to define for
58 # IPython at the system command line. Any parameters you want to define for
59 # configuration can thus be specified here.
59 # configuration can thus be specified here.
60 ipshell = InteractiveShellEmbed(config=cfg,
60 ipshell = InteractiveShellEmbed(config=cfg,
61 banner1 = 'Dropping into IPython',
61 banner1 = 'Dropping into IPython',
62 exit_msg = 'Leaving Interpreter, back to program.')
62 exit_msg = 'Leaving Interpreter, back to program.')
63
63
64 # Make a second instance, you can have as many as you want.
64 # Make a second instance, you can have as many as you want.
65 ipshell2 = InteractiveShellEmbed(config=cfg,
65 ipshell2 = InteractiveShellEmbed(config=cfg,
66 banner1 = 'Second IPython instance.')
66 banner1 = 'Second IPython instance.')
67
67
68 print('\nHello. This is printed from the main controller program.\n')
68 print('\nHello. This is printed from the main controller program.\n')
69
69
70 # You can then call ipshell() anywhere you need it (with an optional
70 # You can then call ipshell() anywhere you need it (with an optional
71 # message):
71 # message):
72 ipshell('***Called from top level. '
72 ipshell('***Called from top level. '
73 'Hit Ctrl-D to exit interpreter and continue program.\n'
73 'Hit Ctrl-D to exit interpreter and continue program.\n'
74 'Note that if you use %kill_embedded, you can fully deactivate\n'
74 'Note that if you use %kill_embedded, you can fully deactivate\n'
75 'This embedded instance so it will never turn on again')
75 'This embedded instance so it will never turn on again')
76
76
77 print('\nBack in caller program, moving along...\n')
77 print('\nBack in caller program, moving along...\n')
78
78
79 #---------------------------------------------------------------------------
79 #---------------------------------------------------------------------------
80 # More details:
80 # More details:
81
81
82 # InteractiveShellEmbed instances don't print the standard system banner and
82 # InteractiveShellEmbed instances don't print the standard system banner and
83 # messages. The IPython banner (which actually may contain initialization
83 # messages. The IPython banner (which actually may contain initialization
84 # messages) is available as get_ipython().banner in case you want it.
84 # messages) is available as get_ipython().banner in case you want it.
85
85
86 # InteractiveShellEmbed instances print the following information every time they
86 # InteractiveShellEmbed instances print the following information every time they
87 # start:
87 # start:
88
88
89 # - A global startup banner.
89 # - A global startup banner.
90
90
91 # - A call-specific header string, which you can use to indicate where in the
91 # - A call-specific header string, which you can use to indicate where in the
92 # execution flow the shell is starting.
92 # execution flow the shell is starting.
93
93
94 # They also print an exit message every time they exit.
94 # They also print an exit message every time they exit.
95
95
96 # Both the startup banner and the exit message default to None, and can be set
96 # Both the startup banner and the exit message default to None, and can be set
97 # either at the instance constructor or at any other time with the
97 # either at the instance constructor or at any other time with the
98 # by setting the banner and exit_msg attributes.
98 # by setting the banner and exit_msg attributes.
99
99
100 # The shell instance can be also put in 'dummy' mode globally or on a per-call
100 # The shell instance can be also put in 'dummy' mode globally or on a per-call
101 # basis. This gives you fine control for debugging without having to change
101 # basis. This gives you fine control for debugging without having to change
102 # code all over the place.
102 # code all over the place.
103
103
104 # The code below illustrates all this.
104 # The code below illustrates all this.
105
105
106
106
107 # This is how the global banner and exit_msg can be reset at any point
107 # This is how the global banner and exit_msg can be reset at any point
108 ipshell.banner2 = 'Entering interpreter - New Banner'
108 ipshell.banner2 = 'Entering interpreter - New Banner'
109 ipshell.exit_msg = 'Leaving interpreter - New exit_msg'
109 ipshell.exit_msg = 'Leaving interpreter - New exit_msg'
110
110
111 def foo(m):
111 def foo(m):
112 s = 'spam'
112 s = 'spam'
113 ipshell('***In foo(). Try %whos, or print s or m:')
113 ipshell('***In foo(). Try %whos, or print s or m:')
114 print('foo says m = ',m)
114 print('foo says m = ',m)
115
115
116 def bar(n):
116 def bar(n):
117 s = 'eggs'
117 s = 'eggs'
118 ipshell('***In bar(). Try %whos, or print s or n:')
118 ipshell('***In bar(). Try %whos, or print s or n:')
119 print('bar says n = ',n)
119 print('bar says n = ',n)
120
120
121 # Some calls to the above functions which will trigger IPython:
121 # Some calls to the above functions which will trigger IPython:
122 print('Main program calling foo("eggs")\n')
122 print('Main program calling foo("eggs")\n')
123 foo('eggs')
123 foo('eggs')
124
124
125 # The shell can be put in 'dummy' mode where calls to it silently return. This
125 # The shell can be put in 'dummy' mode where calls to it silently return. This
126 # allows you, for example, to globally turn off debugging for a program with a
126 # allows you, for example, to globally turn off debugging for a program with a
127 # single call.
127 # single call.
128 ipshell.dummy_mode = True
128 ipshell.dummy_mode = True
129 print('\nTrying to call IPython which is now "dummy":')
129 print('\nTrying to call IPython which is now "dummy":')
130 ipshell()
130 ipshell()
131 print('Nothing happened...')
131 print('Nothing happened...')
132 # The global 'dummy' mode can still be overridden for a single call
132 # The global 'dummy' mode can still be overridden for a single call
133 print('\nOverriding dummy mode manually:')
133 print('\nOverriding dummy mode manually:')
134 ipshell(dummy=False)
134 ipshell(dummy=False)
135
135
136 # Reactivate the IPython shell
136 # Reactivate the IPython shell
137 ipshell.dummy_mode = False
137 ipshell.dummy_mode = False
138
138
139 print('You can even have multiple embedded instances:')
139 print('You can even have multiple embedded instances:')
140 ipshell2()
140 ipshell2()
141
141
142 print('\nMain program calling bar("spam")\n')
142 print('\nMain program calling bar("spam")\n')
143 bar('spam')
143 bar('spam')
144
144
145 print('Main program finished. Bye!')
145 print('Main program finished. Bye!')
@@ -1,26 +1,22 b''
1 """This is an example that shows how to create new prompts for IPython
1 """This is an example that shows how to create new prompts for IPython
2 """
2 """
3
3
4 from IPython.terminal.prompts import Prompts, Token
4 from IPython.terminal.prompts import Prompts, Token
5 import os
5 import os
6
6
7 class MyPrompt(Prompts):
7 class MyPrompt(Prompts):
8
8
9 def in_prompt_tokens(self, cli=None):
9 def in_prompt_tokens(self):
10 return [(Token, os.getcwd()),
10 return [(Token, os.getcwd()), (Token.Prompt, ">>>")]
11 (Token.Prompt, '>>>')]
11
12
12
13 def load_ipython_extension(shell):
13 def load_ipython_extension(shell):
14 new_prompts = MyPrompt(shell)
14 new_prompts = MyPrompt(shell)
15 new_prompts.old_prompts = shell.prompts
15 new_prompts.old_prompts = shell.prompts
16 shell.prompts = new_prompts
16 shell.prompts = new_prompts
17
17
18 def unload_ipython_extension(shell):
18 def unload_ipython_extension(shell):
19 if not hasattr(shell.prompts, 'old_prompts'):
19 if not hasattr(shell.prompts, 'old_prompts'):
20 print("cannot unload")
20 print("cannot unload")
21 else:
21 else:
22 shell.prompts = shell.prompts.old_prompts
22 shell.prompts = shell.prompts.old_prompts
23
24
25
26
General Comments 0
You need to be logged in to leave comments. Login now