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