##// END OF EJS Templates
Merge pull request #9471 from takluyver/dont-update-prompt-width...
Matthias Bussonnier -
r22435:d031b96f merge
parent child Browse files
Show More
@@ -0,0 +1,73 b''
1 """Terminal input and output prompts."""
2 from __future__ import print_function
3
4 from pygments.token import Token
5 import sys
6
7 from IPython.core.displayhook import DisplayHook
8
9 class Prompts(object):
10 def __init__(self, shell):
11 self.shell = shell
12
13 def in_prompt_tokens(self, cli=None):
14 return [
15 (Token.Prompt, 'In ['),
16 (Token.PromptNum, str(self.shell.execution_count)),
17 (Token.Prompt, ']: '),
18 ]
19
20 def _width(self):
21 in_tokens = self.in_prompt_tokens()
22 return sum(len(s) for (t, s) in in_tokens)
23
24 def continuation_prompt_tokens(self, cli=None, width=None):
25 if width is None:
26 width = self._width()
27 return [
28 (Token.Prompt, (' ' * (width - 5)) + '...: '),
29 ]
30
31 def rewrite_prompt_tokens(self):
32 width = self._width()
33 return [
34 (Token.Prompt, ('-' * (width - 2)) + '> '),
35 ]
36
37 def out_prompt_tokens(self):
38 return [
39 (Token.OutPrompt, 'Out['),
40 (Token.OutPromptNum, str(self.shell.execution_count)),
41 (Token.OutPrompt, ']: '),
42 ]
43
44 class ClassicPrompts(Prompts):
45 def in_prompt_tokens(self, cli=None):
46 return [
47 (Token.Prompt, '>>> '),
48 ]
49
50 def continuation_prompt_tokens(self, cli=None, width=None):
51 return [
52 (Token.Prompt, '... ')
53 ]
54
55 def rewrite_prompt_tokens(self):
56 return []
57
58 def out_prompt_tokens(self):
59 return []
60
61 class RichPromptDisplayHook(DisplayHook):
62 """Subclass of base display hook using coloured prompt"""
63 def write_output_prompt(self):
64 sys.stdout.write(self.shell.separate_out)
65 self.prompt_end_newline = False
66 if self.do_full_cache:
67 tokens = self.shell.prompts.out_prompt_tokens()
68 if tokens and tokens[-1][1].endswith('\n'):
69 self.prompt_end_newline = True
70 if self.shell.pt_cli:
71 self.shell.pt_cli.print_tokens(tokens)
72 else:
73 print(*(s for t, s in tokens), sep='')
@@ -0,0 +1,26 b''
1 """This is an example that shows how to create new prompts for IPython
2 """
3
4 from IPython.terminal.prompts import Prompts, Token
5 import os
6
7 class MyPrompt(Prompts):
8
9 def in_prompt_tokens(self, cli=None):
10 return [(Token, os.getcwd()),
11 (Token.Prompt, '>>>')]
12
13 def load_ipython_extension(shell):
14 new_prompts = MyPrompt(shell)
15 new_prompts.old_prompts = shell.prompts
16 shell.prompts = new_prompts
17
18 def unload_ipython_extension(shell):
19 if not hasattr(shell.prompts, 'old_prompts'):
20 print("cannot unload")
21 else:
22 shell.prompts = shell.prompts.old_prompts
23
24
25
26
@@ -113,7 +113,7 b' class DisplayHook(Configurable):'
113 """
113 """
114 # Use write, not print which adds an extra space.
114 # Use write, not print which adds an extra space.
115 sys.stdout.write(self.shell.separate_out)
115 sys.stdout.write(self.shell.separate_out)
116 outprompt = self.shell.prompt_manager.render('out')
116 outprompt = 'Out[{}]: '.format(self.shell.execution_count)
117 if self.do_full_cache:
117 if self.do_full_cache:
118 sys.stdout.write(outprompt)
118 sys.stdout.write(outprompt)
119
119
@@ -149,6 +149,9 b' class DisplayHook(Configurable):'
149 """
149 """
150 return self.shell.display_formatter.format(result)
150 return self.shell.display_formatter.format(result)
151
151
152 # This can be set to True by the write_output_prompt method in a subclass
153 prompt_end_newline = False
154
152 def write_format_data(self, format_dict, md_dict=None):
155 def write_format_data(self, format_dict, md_dict=None):
153 """Write the format data dict to the frontend.
156 """Write the format data dict to the frontend.
154
157
@@ -179,8 +182,7 b' class DisplayHook(Configurable):'
179 # because the expansion may add ANSI escapes that will interfere
182 # because the expansion may add ANSI escapes that will interfere
180 # with our ability to determine whether or not we should add
183 # with our ability to determine whether or not we should add
181 # a newline.
184 # a newline.
182 prompt_template = self.shell.prompt_manager.out_template
185 if not self.prompt_end_newline:
183 if prompt_template and not prompt_template.endswith('\n'):
184 # But avoid extraneous empty lines.
186 # But avoid extraneous empty lines.
185 result_repr = '\n' + result_repr
187 result_repr = '\n' + result_repr
186
188
@@ -56,7 +56,6 b' from IPython.core.macro import Macro'
56 from IPython.core.payload import PayloadManager
56 from IPython.core.payload import PayloadManager
57 from IPython.core.prefilter import PrefilterManager
57 from IPython.core.prefilter import PrefilterManager
58 from IPython.core.profiledir import ProfileDir
58 from IPython.core.profiledir import ProfileDir
59 from IPython.core.prompts import PromptManager
60 from IPython.core.usage import default_banner
59 from IPython.core.usage import default_banner
61 from IPython.testing.skipdoctest import skip_doctest_py2, skip_doctest
60 from IPython.testing.skipdoctest import skip_doctest_py2, skip_doctest
62 from IPython.utils import PyColorize
61 from IPython.utils import PyColorize
@@ -664,8 +663,6 b' class InteractiveShell(SingletonConfigurable):'
664 io.stderr = io.IOStream(sys.stderr)
663 io.stderr = io.IOStream(sys.stderr)
665
664
666 def init_prompts(self):
665 def init_prompts(self):
667 self.prompt_manager = PromptManager(shell=self, parent=self)
668 self.configurables.append(self.prompt_manager)
669 # Set system prompts, so that scripts can decide if they are running
666 # Set system prompts, so that scripts can decide if they are running
670 # interactively.
667 # interactively.
671 sys.ps1 = 'In : '
668 sys.ps1 = 'In : '
@@ -2339,16 +2336,9 b' class InteractiveShell(SingletonConfigurable):'
2339 """
2336 """
2340 if not self.show_rewritten_input:
2337 if not self.show_rewritten_input:
2341 return
2338 return
2342
2343 rw = self.prompt_manager.render('rewrite') + cmd
2344
2339
2345 try:
2340 # This is overridden in TerminalInteractiveShell to use fancy prompts
2346 # plain ascii works better w/ pyreadline, on some machines, so
2341 print("------> " + cmd)
2347 # we use it and only print uncolored rewrite if we have unicode
2348 rw = str(rw)
2349 print(rw)
2350 except UnicodeEncodeError:
2351 print("------> " + cmd)
2352
2342
2353 #-------------------------------------------------------------------------
2343 #-------------------------------------------------------------------------
2354 # Things related to extracting values/expressions from kernel and user_ns
2344 # Things related to extracting values/expressions from kernel and user_ns
@@ -3233,6 +3223,11 b' class InteractiveShell(SingletonConfigurable):'
3233 self.restore_sys_module_state()
3223 self.restore_sys_module_state()
3234
3224
3235
3225
3226 # Overridden in terminal subclass to change prompts
3227 def switch_doctest_mode(self, mode):
3228 pass
3229
3230
3236 class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
3231 class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
3237 """An abstract base class for InteractiveShell."""
3232 """An abstract base class for InteractiveShell."""
3238
3233
@@ -356,14 +356,6 b' Defaulting color scheme to \'NoColor\'"""'
356 # Will remove this check after switching to prompt_toolkit
356 # Will remove this check after switching to prompt_toolkit
357 new_scheme = 'NoColor'
357 new_scheme = 'NoColor'
358
358
359 # Set prompt colors
360 try:
361 shell.prompt_manager.color_scheme = new_scheme
362 except:
363 color_switch_err('prompt')
364 else:
365 shell.colors = \
366 shell.prompt_manager.color_scheme_table.active_scheme_name
367 # Set exception colors
359 # Set exception colors
368 try:
360 try:
369 shell.InteractiveTB.set_colors(scheme = new_scheme)
361 shell.InteractiveTB.set_colors(scheme = new_scheme)
@@ -435,7 +427,6 b' Defaulting color scheme to \'NoColor\'"""'
435
427
436 # Shorthands
428 # Shorthands
437 shell = self.shell
429 shell = self.shell
438 pm = shell.prompt_manager
439 meta = shell.meta
430 meta = shell.meta
440 disp_formatter = self.shell.display_formatter
431 disp_formatter = self.shell.display_formatter
441 ptformatter = disp_formatter.formatters['text/plain']
432 ptformatter = disp_formatter.formatters['text/plain']
@@ -450,23 +441,17 b' Defaulting color scheme to \'NoColor\'"""'
450 save_dstore('xmode',shell.InteractiveTB.mode)
441 save_dstore('xmode',shell.InteractiveTB.mode)
451 save_dstore('rc_separate_out',shell.separate_out)
442 save_dstore('rc_separate_out',shell.separate_out)
452 save_dstore('rc_separate_out2',shell.separate_out2)
443 save_dstore('rc_separate_out2',shell.separate_out2)
453 save_dstore('rc_prompts_pad_left',pm.justify)
454 save_dstore('rc_separate_in',shell.separate_in)
444 save_dstore('rc_separate_in',shell.separate_in)
455 save_dstore('rc_active_types',disp_formatter.active_types)
445 save_dstore('rc_active_types',disp_formatter.active_types)
456 save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template))
457
446
458 if not mode:
447 if not mode:
459 # turn on
448 # turn on
460 pm.in_template = '>>> '
461 pm.in2_template = '... '
462 pm.out_template = ''
463
449
464 # Prompt separators like plain python
450 # Prompt separators like plain python
465 shell.separate_in = ''
451 shell.separate_in = ''
466 shell.separate_out = ''
452 shell.separate_out = ''
467 shell.separate_out2 = ''
453 shell.separate_out2 = ''
468
454
469 pm.justify = False
470
455
471 ptformatter.pprint = False
456 ptformatter.pprint = False
472 disp_formatter.active_types = ['text/plain']
457 disp_formatter.active_types = ['text/plain']
@@ -474,22 +459,22 b' Defaulting color scheme to \'NoColor\'"""'
474 shell.magic('xmode Plain')
459 shell.magic('xmode Plain')
475 else:
460 else:
476 # turn off
461 # turn off
477 pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates
478
479 shell.separate_in = dstore.rc_separate_in
462 shell.separate_in = dstore.rc_separate_in
480
463
481 shell.separate_out = dstore.rc_separate_out
464 shell.separate_out = dstore.rc_separate_out
482 shell.separate_out2 = dstore.rc_separate_out2
465 shell.separate_out2 = dstore.rc_separate_out2
483
466
484 pm.justify = dstore.rc_prompts_pad_left
485
486 ptformatter.pprint = dstore.rc_pprint
467 ptformatter.pprint = dstore.rc_pprint
487 disp_formatter.active_types = dstore.rc_active_types
468 disp_formatter.active_types = dstore.rc_active_types
488
469
489 shell.magic('xmode ' + dstore.xmode)
470 shell.magic('xmode ' + dstore.xmode)
490
471
472 # mode here is the state before we switch; switch_doctest_mode takes
473 # the mode we're switching to.
474 shell.switch_doctest_mode(not mode)
475
491 # Store new mode and inform
476 # Store new mode and inform
492 dstore.mode = bool(1-int(mode))
477 dstore.mode = bool(not mode)
493 mode_label = ['OFF','ON'][dstore.mode]
478 mode_label = ['OFF','ON'][dstore.mode]
494 print('Doctest mode is:', mode_label)
479 print('Doctest mode is:', mode_label)
495
480
@@ -1,37 +1,8 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Classes for handling input/output prompts."""
2 """Being removed
3 """
3
4
4 # Copyright (c) 2001-2007 Fernando Perez <fperez@colorado.edu>
5 from IPython.utils import py3compat
5 # Copyright (c) IPython Development Team.
6 # Distributed under the terms of the Modified BSD License.
7
8 import os
9 import re
10 import socket
11 import sys
12 import time
13
14 from string import Formatter
15
16 from traitlets.config.configurable import Configurable
17 from IPython.core import release
18 from IPython.utils import coloransi, py3compat
19 from traitlets import Unicode, Instance, Dict, Bool, Int, observe, default
20
21 from IPython.utils.PyColorize import LightBGColors, LinuxColors, NoColor
22
23 #-----------------------------------------------------------------------------
24 # Color schemes for prompts
25 #-----------------------------------------------------------------------------
26
27 InputColors = coloransi.InputTermColors # just a shorthand
28 Colors = coloransi.TermColors # just a shorthand
29
30 color_lists = dict(normal=Colors(), inp=InputColors(), nocolor=coloransi.NoColors())
31
32 #-----------------------------------------------------------------------------
33 # Utilities
34 #-----------------------------------------------------------------------------
35
6
36 class LazyEvaluate(object):
7 class LazyEvaluate(object):
37 """This is used for formatting strings with values that need to be updated
8 """This is used for formatting strings with values that need to be updated
@@ -53,360 +24,3 b' class LazyEvaluate(object):'
53
24
54 def __format__(self, format_spec):
25 def __format__(self, format_spec):
55 return format(self(), format_spec)
26 return format(self(), format_spec)
56
57 def multiple_replace(dict, text):
58 """ Replace in 'text' all occurrences of any key in the given
59 dictionary by its corresponding value. Returns the new string."""
60
61 # Function by Xavier Defrang, originally found at:
62 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
63
64 # Create a regular expression from the dictionary keys
65 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
66 # For each match, look-up corresponding value in dictionary
67 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
68
69 #-----------------------------------------------------------------------------
70 # Special characters that can be used in prompt templates, mainly bash-like
71 #-----------------------------------------------------------------------------
72
73 # If $HOME isn't defined (Windows), make it an absurd string so that it can
74 # never be expanded out into '~'. Basically anything which can never be a
75 # reasonable directory name will do, we just want the $HOME -> '~' operation
76 # to become a no-op. We pre-compute $HOME here so it's not done on every
77 # prompt call.
78
79 # FIXME:
80
81 # - This should be turned into a class which does proper namespace management,
82 # since the prompt specials need to be evaluated in a certain namespace.
83 # Currently it's just globals, which need to be managed manually by code
84 # below.
85
86 # - I also need to split up the color schemes from the prompt specials
87 # somehow. I don't have a clean design for that quite yet.
88
89 HOME = py3compat.str_to_unicode(os.environ.get("HOME","//////:::::ZZZZZ,,,~~~"))
90
91 # This is needed on FreeBSD, and maybe other systems which symlink /home to
92 # /usr/home, but retain the $HOME variable as pointing to /home
93 HOME = os.path.realpath(HOME)
94
95 # We precompute a few more strings here for the prompt_specials, which are
96 # fixed once ipython starts. This reduces the runtime overhead of computing
97 # prompt strings.
98 USER = py3compat.str_to_unicode(os.environ.get("USER",''))
99 HOSTNAME = py3compat.str_to_unicode(socket.gethostname())
100 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
101
102 # IronPython doesn't currently have os.getuid() even if
103 # os.name == 'posix'; 2/8/2014
104 ROOT_SYMBOL = "#" if (os.name=='nt' or sys.platform=='cli' or os.getuid()==0) else "$"
105
106 prompt_abbreviations = {
107 # Prompt/history count
108 '%n' : '{color.number}' '{count}' '{color.prompt}',
109 r'\#': '{color.number}' '{count}' '{color.prompt}',
110 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
111 # can get numbers displayed in whatever color they want.
112 r'\N': '{count}',
113
114 # Prompt/history count, with the actual digits replaced by dots or
115 # spaces. Used mainly in continuation prompts (prompt_in2).
116 r'\D': '{dots}',
117 r'\S': '{spaces}',
118
119 # Current time
120 r'\T' : '{time}',
121 # Current working directory
122 r'\w': '{cwd}',
123 # Basename of current working directory.
124 # (use os.sep to make this portable across OSes)
125 r'\W' : '{cwd_last}',
126 # These X<N> are an extension to the normal bash prompts. They return
127 # N terms of the path, after replacing $HOME with '~'
128 r'\X0': '{cwd_x[0]}',
129 r'\X1': '{cwd_x[1]}',
130 r'\X2': '{cwd_x[2]}',
131 r'\X3': '{cwd_x[3]}',
132 r'\X4': '{cwd_x[4]}',
133 r'\X5': '{cwd_x[5]}',
134 # Y<N> are similar to X<N>, but they show '~' if it's the directory
135 # N+1 in the list. Somewhat like %cN in tcsh.
136 r'\Y0': '{cwd_y[0]}',
137 r'\Y1': '{cwd_y[1]}',
138 r'\Y2': '{cwd_y[2]}',
139 r'\Y3': '{cwd_y[3]}',
140 r'\Y4': '{cwd_y[4]}',
141 r'\Y5': '{cwd_y[5]}',
142 # Hostname up to first .
143 r'\h': HOSTNAME_SHORT,
144 # Full hostname
145 r'\H': HOSTNAME,
146 # Username of current user
147 r'\u': USER,
148 # Escaped '\'
149 '\\\\': '\\',
150 # Newline
151 r'\n': '\n',
152 # Carriage return
153 r'\r': '\r',
154 # Release version
155 r'\v': release.version,
156 # Root symbol ($ or #)
157 r'\$': ROOT_SYMBOL,
158 }
159
160 #-----------------------------------------------------------------------------
161 # More utilities
162 #-----------------------------------------------------------------------------
163
164 def cwd_filt(depth):
165 """Return the last depth elements of the current working directory.
166
167 $HOME is always replaced with '~'.
168 If depth==0, the full path is returned."""
169
170 cwd = py3compat.getcwd().replace(HOME,"~")
171 out = os.sep.join(cwd.split(os.sep)[-depth:])
172 return out or os.sep
173
174 def cwd_filt2(depth):
175 """Return the last depth elements of the current working directory.
176
177 $HOME is always replaced with '~'.
178 If depth==0, the full path is returned."""
179
180 full_cwd = py3compat.getcwd()
181 cwd = full_cwd.replace(HOME,"~").split(os.sep)
182 if '~' in cwd and len(cwd) == depth+1:
183 depth += 1
184 drivepart = ''
185 if sys.platform == 'win32' and len(cwd) > depth:
186 drivepart = os.path.splitdrive(full_cwd)[0]
187 out = drivepart + '/'.join(cwd[-depth:])
188
189 return out or os.sep
190
191 #-----------------------------------------------------------------------------
192 # Prompt classes
193 #-----------------------------------------------------------------------------
194
195 lazily_evaluate = {'time': LazyEvaluate(time.strftime, "%H:%M:%S"),
196 'cwd': LazyEvaluate(py3compat.getcwd),
197 'cwd_last': LazyEvaluate(lambda: py3compat.getcwd().split(os.sep)[-1]),
198 'cwd_x': [LazyEvaluate(lambda: py3compat.getcwd().replace(HOME,"~"))] +\
199 [LazyEvaluate(cwd_filt, x) for x in range(1,6)],
200 'cwd_y': [LazyEvaluate(cwd_filt2, x) for x in range(6)]
201 }
202
203 def _lenlastline(s):
204 """Get the length of the last line. More intelligent than
205 len(s.splitlines()[-1]).
206 """
207 if not s or s.endswith(('\n', '\r')):
208 return 0
209 return len(s.splitlines()[-1])
210
211
212 invisible_chars_re = re.compile('\001[^\001\002]*\002')
213 def _invisible_characters(s):
214 """
215 Get the number of invisible ANSI characters in s. Invisible characters
216 must be delimited by \001 and \002.
217 """
218 return _lenlastline(s) - _lenlastline(invisible_chars_re.sub('', s))
219
220 class UserNSFormatter(Formatter):
221 """A Formatter that falls back on a shell's user_ns and __builtins__ for name resolution"""
222 def __init__(self, shell):
223 self.shell = shell
224
225 def get_value(self, key, args, kwargs):
226 # try regular formatting first:
227 try:
228 return Formatter.get_value(self, key, args, kwargs)
229 except Exception:
230 pass
231 # next, look in user_ns and builtins:
232 for container in (self.shell.user_ns, __builtins__):
233 if key in container:
234 return container[key]
235 # nothing found, put error message in its place
236 return "<ERROR: '%s' not found>" % key
237
238
239 class PromptManager(Configurable):
240 """This is the primary interface for producing IPython's prompts."""
241 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
242
243 color_scheme_table = Instance(coloransi.ColorSchemeTable, allow_none=True)
244 color_scheme = Unicode('Linux').tag(config=True)
245
246 @observe('color_scheme')
247 def _color_scheme_changed(self, change):
248 self.color_scheme_table.set_active_scheme(change['new'])
249 for pname in ['in', 'in2', 'out', 'rewrite']:
250 # We need to recalculate the number of invisible characters
251 self.update_prompt(pname)
252
253 lazy_evaluate_fields = Dict(help="""
254 This maps field names used in the prompt templates to functions which
255 will be called when the prompt is rendered. This allows us to include
256 things like the current time in the prompts. Functions are only called
257 if they are used in the prompt.
258 """)
259
260 in_template = Unicode('In [\\#]: ',
261 help="Input prompt. '\\#' will be transformed to the prompt number"
262 ).tag(config=True)
263 in2_template = Unicode(' .\\D.: ',
264 help="Continuation prompt.").tag(config=True)
265 out_template = Unicode('Out[\\#]: ',
266 help="Output prompt. '\\#' will be transformed to the prompt number"
267 ).tag(config=True)
268
269 @default('lazy_evaluate_fields')
270 def _lazy_evaluate_fields_default(self):
271 return lazily_evaluate.copy()
272
273 justify = Bool(True, help="""
274 If True (default), each prompt will be right-aligned with the
275 preceding one.
276 """).tag(config=True)
277
278 # We actually store the expanded templates here:
279 templates = Dict()
280
281 # The number of characters in the last prompt rendered, not including
282 # colour characters.
283 width = Int()
284 txtwidth = Int() # Not including right-justification
285
286 # The number of characters in each prompt which don't contribute to width
287 invisible_chars = Dict()
288
289 @default('invisible_chars')
290 def _invisible_chars_default(self):
291 return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0}
292
293 def __init__(self, shell, **kwargs):
294 super(PromptManager, self).__init__(shell=shell, **kwargs)
295
296 # Prepare colour scheme table
297 self.color_scheme_table = coloransi.ColorSchemeTable([NoColor,
298 LinuxColors, LightBGColors], self.color_scheme)
299
300 self._formatter = UserNSFormatter(shell)
301 # Prepare templates & numbers of invisible characters
302 self.update_prompt('in', self.in_template)
303 self.update_prompt('in2', self.in2_template)
304 self.update_prompt('out', self.out_template)
305 self.update_prompt('rewrite')
306 self.observe(self._update_prompt_trait,
307 names=['in_template', 'in2_template', 'out_template'])
308
309 def update_prompt(self, name, new_template=None):
310 """This is called when a prompt template is updated. It processes
311 abbreviations used in the prompt template (like \#) and calculates how
312 many invisible characters (ANSI colour escapes) the resulting prompt
313 contains.
314
315 It is also called for each prompt on changing the colour scheme. In both
316 cases, traitlets should take care of calling this automatically.
317 """
318 if new_template is not None:
319 self.templates[name] = multiple_replace(prompt_abbreviations, new_template)
320 # We count invisible characters (colour escapes) on the last line of the
321 # prompt, to calculate the width for lining up subsequent prompts.
322 invis_chars = _invisible_characters(self._render(name, color=True))
323 self.invisible_chars[name] = invis_chars
324
325 def _update_prompt_trait(self, changes):
326 traitname = changes['name']
327 new_template = changes['new']
328 name = traitname[:-9] # Cut off '_template'
329 self.update_prompt(name, new_template)
330
331 def _render(self, name, color=True, **kwargs):
332 """Render but don't justify, or update the width or txtwidth attributes.
333 """
334 if name == 'rewrite':
335 return self._render_rewrite(color=color)
336
337 if color:
338 scheme = self.color_scheme_table.active_colors
339 if name=='out':
340 colors = color_lists['normal']
341 colors.number, colors.prompt, colors.normal = \
342 scheme.out_number, scheme.out_prompt, scheme.normal
343 else:
344 colors = color_lists['inp']
345 colors.number, colors.prompt, colors.normal = \
346 scheme.in_number, scheme.in_prompt, scheme.in_normal
347 if name=='in2':
348 colors.prompt = scheme.in_prompt2
349 else:
350 # No color
351 colors = color_lists['nocolor']
352 colors.number, colors.prompt, colors.normal = '', '', ''
353
354 count = self.shell.execution_count # Shorthand
355 # Build the dictionary to be passed to string formatting
356 fmtargs = dict(color=colors, count=count,
357 dots="."*len(str(count)), spaces=" "*len(str(count)),
358 width=self.width, txtwidth=self.txtwidth)
359 fmtargs.update(self.lazy_evaluate_fields)
360 fmtargs.update(kwargs)
361
362 # Prepare the prompt
363 prompt = colors.prompt + self.templates[name] + colors.normal
364
365 # Fill in required fields
366 return self._formatter.format(prompt, **fmtargs)
367
368 def _render_rewrite(self, color=True):
369 """Render the ---> rewrite prompt."""
370 if color:
371 scheme = self.color_scheme_table.active_colors
372 # We need a non-input version of these escapes
373 color_prompt = scheme.in_prompt.replace("\001","").replace("\002","")
374 color_normal = scheme.normal
375 else:
376 color_prompt, color_normal = '', ''
377
378 return color_prompt + "-> ".rjust(self.txtwidth, "-") + color_normal
379
380 def render(self, name, color=True, just=None, **kwargs):
381 """
382 Render the selected prompt.
383
384 Parameters
385 ----------
386 name : str
387 Which prompt to render. One of 'in', 'in2', 'out', 'rewrite'
388 color : bool
389 If True (default), include ANSI escape sequences for a coloured prompt.
390 just : bool
391 If True, justify the prompt to the width of the last prompt. The
392 default is stored in self.justify.
393 **kwargs :
394 Additional arguments will be passed to the string formatting operation,
395 so they can override the values that would otherwise fill in the
396 template.
397
398 Returns
399 -------
400 A string containing the rendered prompt.
401 """
402 res = self._render(name, color=color, **kwargs)
403
404 # Handle justification of prompt
405 invis_chars = self.invisible_chars[name] if color else 0
406 self.txtwidth = _lenlastline(res) - invis_chars
407 just = self.justify if (just is None) else just
408 # If the prompt spans more than one line, don't try to justify it:
409 if just and name != 'in' and ('\n' not in res) and ('\r' not in res):
410 res = res.rjust(self.width + invis_chars)
411 self.width = _lenlastline(res) - invis_chars
412 return res
@@ -3,75 +3,14 b''
3
3
4 import unittest
4 import unittest
5
5
6 import os
6 from IPython.core.prompts import LazyEvaluate
7
8 from IPython.testing import tools as tt, decorators as dec
9 from IPython.core.prompts import PromptManager, LazyEvaluate, _invisible_characters
10 from IPython.testing.globalipapp import get_ipython
7 from IPython.testing.globalipapp import get_ipython
11 from IPython.utils.tempdir import TemporaryWorkingDirectory
12 from IPython.utils import py3compat
13 from IPython.utils.py3compat import unicode_type
8 from IPython.utils.py3compat import unicode_type
14
9
15 ip = get_ipython()
10 ip = get_ipython()
16
11
17
12
18 class PromptTests(unittest.TestCase):
13 class PromptTests(unittest.TestCase):
19 def setUp(self):
20 self.pm = PromptManager(shell=ip, config=ip.config)
21
22 def test_multiline_prompt(self):
23 self.pm.in_template = "[In]\n>>>"
24 self.pm.render('in')
25 self.assertEqual(self.pm.width, 3)
26 self.assertEqual(self.pm.txtwidth, 3)
27
28 self.pm.in_template = '[In]\n'
29 self.pm.render('in')
30 self.assertEqual(self.pm.width, 0)
31 self.assertEqual(self.pm.txtwidth, 0)
32
33 def test_translate_abbreviations(self):
34 def do_translate(template):
35 self.pm.in_template = template
36 return self.pm.templates['in']
37
38 pairs = [(r'%n>', '{color.number}{count}{color.prompt}>'),
39 (r'\T', '{time}'),
40 (r'\n', '\n')
41 ]
42
43 tt.check_pairs(do_translate, pairs)
44
45 def test_user_ns(self):
46 self.pm.color_scheme = 'NoColor'
47 ip.ex("foo='bar'")
48 self.pm.in_template = "In [{foo}]"
49 prompt = self.pm.render('in')
50 self.assertEqual(prompt, u'In [bar]')
51
52 def test_builtins(self):
53 self.pm.color_scheme = 'NoColor'
54 self.pm.in_template = "In [{int}]"
55 prompt = self.pm.render('in')
56 self.assertEqual(prompt, u"In [%r]" % int)
57
58 def test_undefined(self):
59 self.pm.color_scheme = 'NoColor'
60 self.pm.in_template = "In [{foo_dne}]"
61 prompt = self.pm.render('in')
62 self.assertEqual(prompt, u"In [<ERROR: 'foo_dne' not found>]")
63
64 def test_render(self):
65 self.pm.in_template = r'\#>'
66 self.assertEqual(self.pm.render('in',color=False), '%d>' % ip.execution_count)
67
68 @dec.onlyif_unicode_paths
69 def test_render_unicode_cwd(self):
70 with TemporaryWorkingDirectory(u'ΓΌnicΓΈdΓ©'):
71 self.pm.in_template = r'\w [\#]'
72 p = self.pm.render('in', color=False)
73 self.assertEqual(p, u"%s [%i]" % (py3compat.getcwd(), ip.execution_count))
74
75 def test_lazy_eval_unicode(self):
14 def test_lazy_eval_unicode(self):
76 u = u'ΓΌnicΓΈdΓ©'
15 u = u'ΓΌnicΓΈdΓ©'
77 lz = LazyEvaluate(lambda : u)
16 lz = LazyEvaluate(lambda : u)
@@ -95,35 +34,4 b' class PromptTests(unittest.TestCase):'
95 self.assertEqual(unicode_type(lz), unicode_type(f))
34 self.assertEqual(unicode_type(lz), unicode_type(f))
96 self.assertEqual(format(lz), str(f))
35 self.assertEqual(format(lz), str(f))
97 self.assertEqual(format(lz, '.1'), '0.5')
36 self.assertEqual(format(lz, '.1'), '0.5')
98
99 @dec.skip_win32
100 def test_cwd_x(self):
101 self.pm.in_template = r"\X0"
102 save = py3compat.getcwd()
103 os.chdir(os.path.expanduser('~'))
104 p = self.pm.render('in', color=False)
105 try:
106 self.assertEqual(p, '~')
107 finally:
108 os.chdir(save)
109
110 def test_invisible_chars(self):
111 self.assertEqual(_invisible_characters('abc'), 0)
112 self.assertEqual(_invisible_characters('\001\033[1;37m\002'), 9)
113 # Sequences must be between \001 and \002 to be counted
114 self.assertEqual(_invisible_characters('\033[1;37m'), 0)
115 # Test custom escape sequences
116 self.assertEqual(_invisible_characters('\001\033]133;A\a\002'), 10)
117
118 def test_width(self):
119 default_in = '\x01\x1b]133;A\x07\x02In [1]: \x01\x1b]133;B\x07\x02'
120 self.pm.in_template = default_in
121 self.pm.render('in')
122 self.assertEqual(self.pm.width, 8)
123 self.assertEqual(self.pm.txtwidth, 8)
124
37
125 # Test custom escape sequences
126 self.pm.in_template = '\001\033]133;A\a\002' + default_in + '\001\033]133;B\a\002'
127 self.pm.render('in')
128 self.assertEqual(self.pm.width, 8)
129 self.assertEqual(self.pm.txtwidth, 8)
@@ -205,13 +205,6 b' class TestMagicRunPass(tt.TempFileMixin):'
205 _ip = get_ipython()
205 _ip = get_ipython()
206 self.run_tmpfile()
206 self.run_tmpfile()
207 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
207 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
208
209 def test_prompts(self):
210 """Test that prompts correctly generate after %run"""
211 self.run_tmpfile()
212 _ip = get_ipython()
213 p2 = _ip.prompt_manager.render('in2').strip()
214 nt.assert_equal(p2[:3], '...')
215
208
216 def test_run_profile( self ):
209 def test_run_profile( self ):
217 """Test that the option -p, which invokes the profiler, do not
210 """Test that the option -p, which invokes the profiler, do not
@@ -52,10 +52,9 b' class TestFileToRun(unittest.TestCase, tt.TempFileMixin):'
52 src = "True\n"
52 src = "True\n"
53 self.mktmp(src)
53 self.mktmp(src)
54
54
55 out = 'In [1]: False\n\nIn [2]:'
55 out, err = tt.ipexec(self.fname, options=['-i'],
56 err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None
57 tt.ipexec_validate(self.fname, out, err, options=['-i'],
58 commands=['"__file__" in globals()', 'exit()'])
56 commands=['"__file__" in globals()', 'exit()'])
57 self.assertIn("False", out)
59
58
60 @dec.skip_win32
59 @dec.skip_win32
61 @dec.skipif(PY3)
60 @dec.skipif(PY3)
@@ -64,7 +63,6 b' class TestFileToRun(unittest.TestCase, tt.TempFileMixin):'
64 src = "from __future__ import division\n"
63 src = "from __future__ import division\n"
65 self.mktmp(src)
64 self.mktmp(src)
66
65
67 out = 'In [1]: float\n\nIn [2]:'
66 out, err = tt.ipexec(self.fname, options=['-i'],
68 err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None
69 tt.ipexec_validate(self.fname, out, err, options=['-i'],
70 commands=['type(1/2)', 'exit()'])
67 commands=['type(1/2)', 'exit()'])
68 self.assertIn('float', out)
@@ -898,7 +898,6 b' class IPythonDirective(Directive):'
898 if not self.state.document.current_source in self.seen_docs:
898 if not self.state.document.current_source in self.seen_docs:
899 self.shell.IP.history_manager.reset()
899 self.shell.IP.history_manager.reset()
900 self.shell.IP.execution_count = 1
900 self.shell.IP.execution_count = 1
901 self.shell.IP.prompt_manager.width = 0
902 self.seen_docs.add(self.state.document.current_source)
901 self.seen_docs.add(self.state.document.current_source)
903
902
904 # and attach to shell so we don't have to pass them around
903 # and attach to shell so we don't have to pass them around
@@ -614,7 +614,7 b' class TerminalInteractiveShell(InteractiveShell):'
614 self.hooks.pre_prompt_hook()
614 self.hooks.pre_prompt_hook()
615 if more:
615 if more:
616 try:
616 try:
617 prompt = self.prompt_manager.render('in2')
617 prompt = ' ...: '
618 except:
618 except:
619 self.showtraceback()
619 self.showtraceback()
620 if self.autoindent:
620 if self.autoindent:
@@ -622,7 +622,7 b' class TerminalInteractiveShell(InteractiveShell):'
622
622
623 else:
623 else:
624 try:
624 try:
625 prompt = self.separate_in + self.prompt_manager.render('in')
625 prompt = self.separate_in + 'In [{}]: '.format(self.execution_count)
626 except:
626 except:
627 self.showtraceback()
627 self.showtraceback()
628 try:
628 try:
@@ -24,7 +24,6 b' from IPython.core.completer import IPCompleter'
24 from IPython.core.crashhandler import CrashHandler
24 from IPython.core.crashhandler import CrashHandler
25 from IPython.core.formatters import PlainTextFormatter
25 from IPython.core.formatters import PlainTextFormatter
26 from IPython.core.history import HistoryManager
26 from IPython.core.history import HistoryManager
27 from IPython.core.prompts import PromptManager
28 from IPython.core.application import (
27 from IPython.core.application import (
29 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
28 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
30 )
29 )
@@ -195,7 +194,6 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):'
195 InteractiveShellApp, # ShellApp comes before TerminalApp, because
194 InteractiveShellApp, # ShellApp comes before TerminalApp, because
196 self.__class__, # it will also affect subclasses (e.g. QtConsole)
195 self.__class__, # it will also affect subclasses (e.g. QtConsole)
197 TerminalInteractiveShell,
196 TerminalInteractiveShell,
198 PromptManager,
199 HistoryManager,
197 HistoryManager,
200 ProfileDir,
198 ProfileDir,
201 PlainTextFormatter,
199 PlainTextFormatter,
@@ -11,7 +11,7 b' from IPython.core.interactiveshell import InteractiveShell'
11 from IPython.utils.py3compat import cast_unicode_py2, input
11 from IPython.utils.py3compat import cast_unicode_py2, input
12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
13 from IPython.utils.process import abbrev_cwd
13 from IPython.utils.process import abbrev_cwd
14 from traitlets import Bool, Unicode, Dict, Integer, observe
14 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance
15
15
16 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
16 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
17 from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone
17 from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone
@@ -29,6 +29,7 b' from pygments.token import Token'
29 from .debugger import TerminalPdb, Pdb
29 from .debugger import TerminalPdb, Pdb
30 from .pt_inputhooks import get_inputhook_func
30 from .pt_inputhooks import get_inputhook_func
31 from .interactiveshell import get_default_editor, TerminalMagics
31 from .interactiveshell import get_default_editor, TerminalMagics
32 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
32 from .ptutils import IPythonPTCompleter, IPythonPTLexer
33 from .ptutils import IPythonPTCompleter, IPythonPTLexer
33
34
34 _use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty()
35 _use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty()
@@ -98,7 +99,19 b' class TerminalInteractiveShell(InteractiveShell):'
98 editor = Unicode(get_default_editor(),
99 editor = Unicode(get_default_editor(),
99 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
100 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
100 ).tag(config=True)
101 ).tag(config=True)
101
102
103 prompts = Instance(Prompts)
104
105 def _prompts_default(self):
106 return Prompts(self)
107
108 @observe('prompts')
109 def _(self, change):
110 self._update_layout()
111
112 def _displayhook_class_default(self):
113 return RichPromptDisplayHook
114
102 term_title = Bool(True,
115 term_title = Bool(True,
103 help="Automatically set the terminal title"
116 help="Automatically set the terminal title"
104 ).tag(config=True)
117 ).tag(config=True)
@@ -120,18 +133,6 b' class TerminalInteractiveShell(InteractiveShell):'
120 else:
133 else:
121 toggle_set_term_title(False)
134 toggle_set_term_title(False)
122
135
123 def get_prompt_tokens(self, cli):
124 return [
125 (Token.Prompt, 'In ['),
126 (Token.PromptNum, str(self.execution_count)),
127 (Token.Prompt, ']: '),
128 ]
129
130 def get_continuation_tokens(self, cli, width):
131 return [
132 (Token.Prompt, (' ' * (width - 5)) + '...: '),
133 ]
134
135 def init_prompt_toolkit_cli(self):
136 def init_prompt_toolkit_cli(self):
136 if self.simple_prompt:
137 if self.simple_prompt:
137 # Fall back to plain non-interactive output for tests.
138 # Fall back to plain non-interactive output for tests.
@@ -234,6 +235,8 b' class TerminalInteractiveShell(InteractiveShell):'
234 style_overrides = {
235 style_overrides = {
235 Token.Prompt: '#009900',
236 Token.Prompt: '#009900',
236 Token.PromptNum: '#00ff00 bold',
237 Token.PromptNum: '#00ff00 bold',
238 Token.OutPrompt: '#990000',
239 Token.OutPromptNum: '#ff0000 bold',
237 }
240 }
238 if name == 'default':
241 if name == 'default':
239 style_cls = get_style_by_name('default')
242 style_cls = get_style_by_name('default')
@@ -261,8 +264,8 b' class TerminalInteractiveShell(InteractiveShell):'
261 return {
264 return {
262 'lexer':IPythonPTLexer(),
265 'lexer':IPythonPTLexer(),
263 'reserve_space_for_menu':self.space_for_menu,
266 'reserve_space_for_menu':self.space_for_menu,
264 'get_prompt_tokens':self.get_prompt_tokens,
267 'get_prompt_tokens':self.prompts.in_prompt_tokens,
265 'get_continuation_tokens':self.get_continuation_tokens,
268 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
266 'multiline':True,
269 'multiline':True,
267 'display_completions_in_columns': self.display_completions_in_columns,
270 'display_completions_in_columns': self.display_completions_in_columns,
268
271
@@ -439,6 +442,29 b' class TerminalInteractiveShell(InteractiveShell):'
439 # work correctly.
442 # work correctly.
440 system = InteractiveShell.system_raw
443 system = InteractiveShell.system_raw
441
444
445 def auto_rewrite_input(self, cmd):
446 """Overridden from the parent class to use fancy rewriting prompt"""
447 if not self.show_rewritten_input:
448 return
449
450 tokens = self.prompts.rewrite_prompt_tokens()
451 if self.pt_cli:
452 self.pt_cli.print_tokens(tokens)
453 print(cmd)
454 else:
455 prompt = ''.join(s for t, s in tokens)
456 print(prompt, cmd, sep='')
457
458 _prompts_before = None
459 def switch_doctest_mode(self, mode):
460 """Switch prompts to classic for %doctest_mode"""
461 if mode:
462 self._prompts_before = self.prompts
463 self.prompts = ClassicPrompts(self)
464 elif self._prompts_before:
465 self.prompts = self._prompts_before
466 self._prompts_before = None
467
442
468
443 if __name__ == '__main__':
469 if __name__ == '__main__':
444 TerminalInteractiveShell.instance().interact()
470 TerminalInteractiveShell.instance().interact()
@@ -202,13 +202,7 b' def ipexec(fname, options=None, commands=()):'
202 """
202 """
203 if options is None: options = []
203 if options is None: options = []
204
204
205 # For these subprocess calls, eliminate all prompt printing so we only see
205 cmdargs = default_argv() + options
206 # output from script execution
207 prompt_opts = [ '--PromptManager.in_template=""',
208 '--PromptManager.in2_template=""',
209 '--PromptManager.out_template=""'
210 ]
211 cmdargs = default_argv() + prompt_opts + options
212
206
213 test_dir = os.path.dirname(__file__)
207 test_dir = os.path.dirname(__file__)
214
208
@@ -2,52 +2,6 b''
2 Specific config details
2 Specific config details
3 =======================
3 =======================
4
4
5 Prompts
6 =======
7
8 In the terminal, the format of the input and output prompts can be
9 customised. This does not currently affect other frontends.
10
11 The following codes in the prompt string will be substituted into the
12 prompt string:
13
14 ====== =================================== =====================================================
15 Short Long Notes
16 ====== =================================== =====================================================
17 %n,\\# {color.number}{count}{color.prompt} history counter with bolding
18 \\N {count} history counter without bolding
19 \\D {dots} series of dots the same width as the history counter
20 \\T {time} current time
21 \\w {cwd} current working directory
22 \\W {cwd_last} basename of CWD
23 \\Xn {cwd_x[n]} Show the last n terms of the CWD. n=0 means show all.
24 \\Yn {cwd_y[n]} Like \Xn, but show '~' for $HOME
25 \\h hostname, up to the first '.'
26 \\H full hostname
27 \\u username (from the $USER environment variable)
28 \\v IPython version
29 \\$ root symbol ("$" for normal user or "#" for root)
30 ``\\`` escaped '\\'
31 \\n newline
32 \\r carriage return
33 n/a {color.<Name>} set terminal colour - see below for list of names
34 ====== =================================== =====================================================
35
36 Available colour names are: Black, BlinkBlack, BlinkBlue, BlinkCyan,
37 BlinkGreen, BlinkLightGray, BlinkPurple, BlinkRed, BlinkYellow, Blue,
38 Brown, Cyan, DarkGray, Green, LightBlue, LightCyan, LightGray, LightGreen,
39 LightPurple, LightRed, Purple, Red, White, Yellow. The selected colour
40 scheme also defines the names *prompt* and *number*. Finally, the name
41 *normal* resets the terminal to its default colour.
42
43 So, this config::
44
45 c.PromptManager.in_template = "{color.LightGreen}{time}{color.Yellow} \u{color.normal}>>>"
46
47 will produce input prompts with the time in light green, your username
48 in yellow, and a ``>>>`` prompt in the default terminal colour.
49
50
51 .. _termcolour:
5 .. _termcolour:
52
6
53 Terminal Colors
7 Terminal Colors
@@ -84,27 +38,10 b' These have shown problems:'
84 extensions. Once Gary's readline library is installed, the normal
38 extensions. Once Gary's readline library is installed, the normal
85 WinXP/2k command prompt works perfectly.
39 WinXP/2k command prompt works perfectly.
86
40
87 Currently the following color schemes are available:
88
89 * NoColor: uses no color escapes at all (all escapes are empty '' ''
90 strings). This 'scheme' is thus fully safe to use in any terminal.
91 * Linux: works well in Linux console type environments: dark
92 background with light fonts. It uses bright colors for
93 information, so it is difficult to read if you have a light
94 colored background.
95 * LightBG: the basic colors are similar to those in the Linux scheme
96 but darker. It is easy to read in terminals with light backgrounds.
97
98 IPython uses colors for two main groups of things: prompts and
41 IPython uses colors for two main groups of things: prompts and
99 tracebacks which are directly printed to the terminal, and the object
42 tracebacks which are directly printed to the terminal, and the object
100 introspection system which passes large sets of data through a pager.
43 introspection system which passes large sets of data through a pager.
101
44
102 If you are seeing garbage sequences in your terminal and no colour, you
103 may need to disable colours: run ``%colors NoColor`` inside IPython, or
104 add this to a config file::
105
106 c.InteractiveShell.colors = 'NoColor'
107
108 Colors in the pager
45 Colors in the pager
109 -------------------
46 -------------------
110
47
@@ -73,11 +73,6 b' Example config file'
73 c.InteractiveShell.editor = 'nano'
73 c.InteractiveShell.editor = 'nano'
74 c.InteractiveShell.xmode = 'Context'
74 c.InteractiveShell.xmode = 'Context'
75
75
76 c.PromptManager.in_template = 'In [\#]: '
77 c.PromptManager.in2_template = ' .\D.: '
78 c.PromptManager.out_template = 'Out[\#]: '
79 c.PromptManager.justify = True
80
81 c.PrefilterManager.multi_line_specials = True
76 c.PrefilterManager.multi_line_specials = True
82
77
83 c.AliasManager.user_aliases = [
78 c.AliasManager.user_aliases = [
@@ -63,20 +63,46 b' switching to any of them. Type ``cd?`` for more details.'
63 Prompt customization
63 Prompt customization
64 ====================
64 ====================
65
65
66 Here are some prompt configurations you can try out interactively by using the
66 Starting at IPython 5.0 the prompt customisation is done by subclassing :class:`IPython.terminal.prompts.Prompt`.
67 ``%config`` magic::
67
68
68 The custom ``Prompt`` receive the current IPython shell instance as first
69 %config PromptManager.in_template = r'{color.LightGreen}\u@\h{color.LightBlue}[{color.LightCyan}\Y1{color.LightBlue}]{color.Green}|\#> '
69 argument, which by default is stored as the ``shell`` attribute of the object.
70 %config PromptManager.in2_template = r'{color.Green}|{color.LightGreen}\D{color.Green}> '
70 The class can implement optional methods for each of the available prompt types:
71 %config PromptManager.out_template = r'<\#> '
71
72
72 - ``in_prompt_tokens(self, cli=None)``, input prompt , default to ``In [1]``
73
73 - ``continuation_prompt_tokens(self, cli=None, width=None)``, continuation prompt for multi lines (default `...:`)
74 You can change the prompt configuration to your liking permanently by editing
74 - ``rewrite_prompt_tokens(self)``
75 ``ipython_config.py``::
75 - ``out_prompt_tokens(self)``
76
76
77 c.PromptManager.in_template = r'{color.LightGreen}\u@\h{color.LightBlue}[{color.LightCyan}\Y1{color.LightBlue}]{color.Green}|\#> '
77 Each of these methods should return a list of `(TokenType, Token)` pairs. See documentation of `prompt_toolkit` and/or `Pygments`.
78 c.PromptManager.in2_template = r'{color.Green}|{color.LightGreen}\D{color.Green}> '
78
79 c.PromptManager.out_template = r'<\#> '
79 Here is an example of Prompt class that will insert the current working directory in front of a prompt:
80
81
82 .. codeblock:: python
83
84 from IPython.terminal.prompts import Prompts, Token
85 import os
86
87 class MyPrompt(Prompts):
88
89 def in_prompt_tokens(self, cli=None):
90 return [(Token, os.getcwd()),
91 (Token.Prompt, ' >>>')]
92
93 To set the new prompt, assign it to the `prompts` attribute of the IPython shell:
94
95 .. codeblock:: python
96
97 In[2]: ip = get_ipython()
98 ...: ip.prompts = MyPrompt(ip)
99
100 ~/ >>> # it works
101
102
103 See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write an
104 extensions that customise prompts.
105
80
106
81 Read more about the :ref:`configuration system <config_overview>` for details
107 Read more about the :ref:`configuration system <config_overview>` for details
82 on how to find ``ipython_config.py``.
108 on how to find ``ipython_config.py``.
General Comments 0
You need to be logged in to leave comments. Login now