Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prompts #1083

Merged
merged 4 commits into from Dec 1, 2011
Merged

Prompts #1083

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 38 additions & 4 deletions IPython/core/interactiveshell.py
Expand Up @@ -315,10 +315,41 @@ def _exiter_default(self):
help="Save multi-line entries as one entry in readline history"
)

prompt_in1 = Unicode('In [\\#]: ', config=True)
prompt_in2 = Unicode(' .\\D.: ', config=True)
prompt_out = Unicode('Out[\\#]: ', config=True)
prompts_pad_left = CBool(True, config=True)
# deprecated prompt traits:

prompt_in1 = Unicode('In [\\#]: ', config=True,
help="Deprecated, use PromptManager.in_template")
prompt_in2 = Unicode(' .\\D.: ', config=True,
help="Deprecated, use PromptManager.in2_template")
prompt_out = Unicode('Out[\\#]: ', config=True,
help="Deprecated, use PromptManager.out_template")
prompts_pad_left = CBool(True, config=True,
help="Deprecated, use PromptManager.justify")

def _prompt_trait_changed(self, name, old, new):
table = {
'prompt_in1' : 'in_template',
'prompt_in2' : 'in2_template',
'prompt_out' : 'out_template',
'prompts_pad_left' : 'justify',
}
warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}\n".format(
name=name, newname=table[name])
)
# protect against weird cases where self.config may not exist:
if self.config is not None:
# propagate to corresponding PromptManager trait
setattr(self.config.PromptManager, table[name], new)

_prompt_in1_changed = _prompt_trait_changed
_prompt_in2_changed = _prompt_trait_changed
_prompt_out_changed = _prompt_trait_changed
_prompt_pad_left_changed = _prompt_trait_changed

show_rewritten_input = CBool(True, config=True,
help="Show rewritten input, e.g. for autocall."
)

quiet = CBool(False, config=True)

history_length = Integer(10000, config=True)
Expand Down Expand Up @@ -2141,6 +2172,9 @@ def auto_rewrite_input(self, cmd):
after the user's input prompt. This helps the user understand that the
input line was transformed automatically by IPython.
"""
if not self.show_rewritten_input:
return

rw = self.prompt_manager.render('rewrite') + cmd

try:
Expand Down
96 changes: 57 additions & 39 deletions IPython/core/prompts.py
Expand Up @@ -254,10 +254,12 @@ def _color_scheme_changed(self, name, new_value):
""")
def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy()

in_template = Unicode('In [\\#]: ', config=True)
in2_template = Unicode(' .\\D.: ', config=True)
out_template = Unicode('Out[\\#]: ', config=True)
rewrite_template = Unicode("------> ", config=True)
in_template = Unicode('In [\\#]: ', config=True,
help="Input prompt. '\\#' will be transformed to the prompt number")
in2_template = Unicode(' .\\D.: ', config=True,
help="Continuation prompt.")
out_template = Unicode('Out[\\#]: ', config=True,
help="Output prompt. '\\#' will be transformed to the prompt number")

justify = Bool(True, config=True, help="""
If True (default), each prompt will be right-aligned with the
Expand All @@ -270,11 +272,12 @@ def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy()
# The number of characters in the last prompt rendered, not including
# colour characters.
width = Int()
txtwidth = Int() # Not including right-justification

# The number of characters in each prompt which don't contribute to width
invisible_chars = Dict()
def _invisible_chars_default(self):
return {'in': 0, 'in2': 0, 'out': 0, 'rewrite': 0}
return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0}

def __init__(self, shell, config=None):
super(PromptManager, self).__init__(shell=shell, config=config)
Expand All @@ -283,13 +286,13 @@ def __init__(self, shell, config=None):
self.color_scheme_table = coloransi.ColorSchemeTable([PColNoColors,
PColLinux, PColLightBG], self.color_scheme)

# Prepare templates
# Prepare templates & numbers of invisible characters
self.update_prompt('in', self.in_template)
self.update_prompt('in2', self.in2_template)
self.update_prompt('out', self.out_template)
self.update_prompt('rewrite', self.rewrite_template)
self.update_prompt('rewrite')
self.on_trait_change(self._update_prompt_trait, ['in_template',
'in2_template', 'out_template', 'rewrite_template'])
'in2_template', 'out_template'])

def update_prompt(self, name, new_template=None):
"""This is called when a prompt template is updated. It processes
Expand All @@ -302,48 +305,26 @@ def update_prompt(self, name, new_template=None):
"""
if new_template is not None:
self.templates[name] = multiple_replace(prompt_abbreviations, new_template)
invis_chars = len(self.render(name, color=True, just=False)) - \
len(self.render(name, color=False, just=False))
invis_chars = len(self._render(name, color=True)) - \
len(self._render(name, color=False))
self.invisible_chars[name] = invis_chars

def _update_prompt_trait(self, traitname, new_template):
name = traitname[:-9] # Cut off '_template'
self.update_prompt(name, new_template)

def render(self, name, color=True, just=None, **kwargs):
def _render(self, name, color=True, **kwargs):
"""Render but don't justify, or update the width or txtwidth attributes.
"""
Render the selected prompt.
if name == 'rewrite':
return self._render_rewrite(color=color)

Parameters
----------
name : str
Which prompt to render. One of 'in', 'in2', 'out', 'rewrite'
color : bool
If True (default), include ANSI escape sequences for a coloured prompt.
just : bool
If True, justify the prompt to the width of the last prompt. The
default is stored in self.justify.
**kwargs :
Additional arguments will be passed to the string formatting operation,
so they can override the values that would otherwise fill in the
template.

Returns
-------
A string containing the rendered prompt.
"""
if color:
scheme = self.color_scheme_table.active_colors
if name=='out':
colors = color_lists['normal']
colors.number, colors.prompt, colors.normal = \
scheme.out_number, scheme.out_prompt, scheme.normal
elif name=='rewrite':
colors = color_lists['normal']
# We need a non-input version of these escapes
colors.number = scheme.in_number.replace("\001","").replace("\002","")
colors.prompt = scheme.in_prompt.replace("\001","").replace("\002","")
colors.normal = scheme.normal
else:
colors = color_lists['inp']
colors.number, colors.prompt, colors.normal = \
Expand All @@ -358,21 +339,58 @@ def render(self, name, color=True, just=None, **kwargs):
count = self.shell.execution_count # Shorthand
# Build the dictionary to be passed to string formatting
fmtargs = dict(color=colors, count=count,
dots="."*len(str(count)) )
dots="."*len(str(count)),
width=self.width, txtwidth=self.txtwidth )
fmtargs.update(self.lazy_evaluate_fields)
fmtargs.update(kwargs)

# Prepare the prompt
prompt = colors.prompt + self.templates[name] + colors.normal

# Fill in required fields
res = prompt.format(**fmtargs)
return prompt.format(**fmtargs)

def _render_rewrite(self, color=True):
"""Render the ---> rewrite prompt."""
if color:
scheme = self.color_scheme_table.active_colors
# We need a non-input version of these escapes
color_prompt = scheme.in_prompt.replace("\001","").replace("\002","")
color_normal = scheme.normal
else:
color_prompt, color_normal = '', ''

return color_prompt + "-> ".rjust(self.txtwidth, "-") + color_normal

def render(self, name, color=True, just=None, **kwargs):
"""
Render the selected prompt.

Parameters
----------
name : str
Which prompt to render. One of 'in', 'in2', 'out', 'rewrite'
color : bool
If True (default), include ANSI escape sequences for a coloured prompt.
just : bool
If True, justify the prompt to the width of the last prompt. The
default is stored in self.justify.
**kwargs :
Additional arguments will be passed to the string formatting operation,
so they can override the values that would otherwise fill in the
template.

Returns
-------
A string containing the rendered prompt.
"""
res = self._render(name, color=color, **kwargs)

# Handle justification of prompt
invis_chars = self.invisible_chars[name] if color else 0
self.txtwidth = len(res) - invis_chars
just = self.justify if (just is None) else just
if just:
res = res.rjust(self.width + invis_chars)
self.width = len(res) - invis_chars
return res

8 changes: 5 additions & 3 deletions IPython/frontend/terminal/ipapp.py
Expand Up @@ -38,6 +38,7 @@
from IPython.core.completer import IPCompleter
from IPython.core.crashhandler import CrashHandler
from IPython.core.formatters import PlainTextFormatter
from IPython.core.prompts import PromptManager
from IPython.core.application import (
ProfileDir, BaseIPythonApplication, base_flags, base_aliases
)
Expand Down Expand Up @@ -133,9 +134,9 @@ def make_report(self,traceback):
classic_config = Config()
classic_config.InteractiveShell.cache_size = 0
classic_config.PlainTextFormatter.pprint = False
classic_config.InteractiveShell.prompt_in1 = '>>> '
classic_config.InteractiveShell.prompt_in2 = '... '
classic_config.InteractiveShell.prompt_out = ''
classic_config.PromptManager.in_template = '>>> '
classic_config.PromptManager.in2_template = '... '
classic_config.PromptManager.out_template = ''
classic_config.InteractiveShell.separate_in = ''
classic_config.InteractiveShell.separate_out = ''
classic_config.InteractiveShell.separate_out2 = ''
Expand Down Expand Up @@ -197,6 +198,7 @@ def _classes_default(self):
InteractiveShellApp, # ShellApp comes before TerminalApp, because
self.__class__, # it will also affect subclasses (e.g. QtConsole)
TerminalInteractiveShell,
PromptManager,
ProfileDir,
PlainTextFormatter,
IPCompleter,
Expand Down
6 changes: 3 additions & 3 deletions IPython/testing/tools.py
Expand Up @@ -202,9 +202,9 @@ def ipexec(fname, options=None):

# For these subprocess calls, eliminate all prompt printing so we only see
# output from script execution
prompt_opts = [ '--InteractiveShell.prompt_in1=""',
'--InteractiveShell.prompt_in2=""',
'--InteractiveShell.prompt_out=""'
prompt_opts = [ '--PromptManager.in_template=""',
'--PromptManager.in2_template=""',
'--PromptManager.out_template=""'
]
cmdargs = ' '.join(default_argv() + prompt_opts + options)

Expand Down
18 changes: 9 additions & 9 deletions docs/examples/core/example-embed.py
Expand Up @@ -23,10 +23,10 @@
except NameError:
nested = 0
cfg = Config()
shell_config = cfg.InteractiveShellEmbed
shell_config.prompt_in1 = 'In <\\#>: '
shell_config.prompt_in2 = ' .\\D.: '
shell_config.prompt_out = 'Out<\\#>: '
prompt_config = cfg.PromptManager
prompt_config.in_template = 'In <\\#>: '
prompt_config.in2_template = ' .\\D.: '
prompt_config.out_template = 'Out<\\#>: '
else:
print "Running nested copies of IPython."
print "The prompts for the nested copy have been modified"
Expand All @@ -46,12 +46,12 @@

# Make a second instance, you can have as many as you want.
cfg2 = cfg.copy()
shell_config = cfg2.InteractiveShellEmbed
shell_config.prompt_in1 = 'In2<\\#>: '
prompt_config = cfg2.PromptManager
prompt_config.in_template = 'In2<\\#>: '
if not nested:
shell_config.prompt_in1 = 'In2<\\#>: '
shell_config.prompt_in2 = ' .\\D.: '
shell_config.prompt_out = 'Out<\\#>: '
prompt_config.in_template = 'In2<\\#>: '
prompt_config.in2_template = ' .\\D.: '
prompt_config.out_template = 'Out<\\#>: '
ipshell2 = InteractiveShellEmbed(config=cfg,
banner1 = 'Second IPython instance.')

Expand Down
8 changes: 4 additions & 4 deletions docs/source/interactive/reference.txt
Expand Up @@ -227,7 +227,7 @@ All options with a [no] prepended can be specified in negated form
circular file inclusions, IPython will stop if it reaches 15
recursive inclusions.

``InteractiveShell.prompt_in1=<string>``
``PromptManager.in_template=<string>``

Specify the string used for input prompts. Note that if you are using
numbered prompts, the number is represented with a '\#' in the
Expand All @@ -236,17 +236,17 @@ All options with a [no] prepended can be specified in negated form
discusses in detail all the available escapes to customize your
prompts.

``InteractiveShell.prompt_in2=<string>``
``PromptManager.in2_template=<string>``
Similar to the previous option, but used for the continuation
prompts. The special sequence '\D' is similar to '\#', but
with all digits replaced dots (so you can have your
continuation prompt aligned with your input prompt). Default:
' .\D.:' (note three spaces at the start for alignment with
'In [\#]').

``InteractiveShell.prompt_out=<string>``
``PromptManager.out_template=<string>``
String used for output prompts, also uses numbers like
prompt_in1. Default: 'Out[\#]:'
in_template. Default: 'Out[\#]:'

``--quick``
start in bare bones mode (no config file loaded).
Expand Down
5 changes: 3 additions & 2 deletions docs/source/interactive/shell.txt
Expand Up @@ -155,8 +155,9 @@ Prompt customization

The sh profile uses the following prompt configurations::

o.prompt_in1= r'\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#>'
o.prompt_in2= r'\C_Green|\C_LightGreen\D\C_Green>'
c.PromptManager.in_template = r'{color.LightGreen}\u@\h{color.LightBlue}[{color.LightCyan}\Y1{color.LightBlue}]{color.Green}|\#> '
c.PromptManager.in2_template = r'{color.Green}|{color.LightGreen}\D{color.Green}> '
c.PromptManager.out_template = r'<\#> '

You can change the prompt configuration to your liking by editing
ipython_config.py.
Expand Down