Show More
@@ -25,7 +25,6 b' Authors:' | |||
|
25 | 25 | import __builtin__ |
|
26 | 26 | |
|
27 | 27 | from IPython.config.configurable import Configurable |
|
28 | from IPython.core import prompts | |
|
29 | 28 | from IPython.utils import io |
|
30 | 29 | from IPython.utils.traitlets import Instance, List |
|
31 | 30 | from IPython.utils.warn import warn |
@@ -34,32 +33,20 b' from IPython.utils.warn import warn' | |||
|
34 | 33 | # Main displayhook class |
|
35 | 34 | #----------------------------------------------------------------------------- |
|
36 | 35 | |
|
37 | # TODO: The DisplayHook class should be split into two classes, one that | |
|
38 | # manages the prompts and their synchronization and another that just does the | |
|
39 | # displayhook logic and calls into the prompt manager. | |
|
40 | ||
|
41 | # TODO: Move the various attributes (cache_size, colors, input_sep, | |
|
42 | # output_sep, output_sep2, ps1, ps2, ps_out, pad_left). Some of these are also | |
|
43 | # attributes of InteractiveShell. They should be on ONE object only and the | |
|
44 | # other objects should ask that one object for their values. | |
|
36 | # TODO: Move the various attributes (cache_size, [others now moved]). Some | |
|
37 | # of these are also attributes of InteractiveShell. They should be on ONE object | |
|
38 | # only and the other objects should ask that one object for their values. | |
|
45 | 39 | |
|
46 | 40 | class DisplayHook(Configurable): |
|
47 | 41 | """The custom IPython displayhook to replace sys.displayhook. |
|
48 | 42 | |
|
49 | 43 | This class does many things, but the basic idea is that it is a callable |
|
50 | 44 | that gets called anytime user code returns a value. |
|
51 | ||
|
52 | Currently this class does more than just the displayhook logic and that | |
|
53 | extra logic should eventually be moved out of here. | |
|
54 | 45 | """ |
|
55 | 46 | |
|
56 | 47 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') |
|
57 | 48 | |
|
58 | def __init__(self, shell=None, cache_size=1000, | |
|
59 | colors='NoColor', input_sep='\n', | |
|
60 | output_sep='\n', output_sep2='', | |
|
61 | ps1 = None, ps2 = None, ps_out = None, pad_left=True, | |
|
62 | config=None): | |
|
49 | def __init__(self, shell=None, cache_size=1000, config=None): | |
|
63 | 50 | super(DisplayHook, self).__init__(shell=shell, config=config) |
|
64 | 51 | |
|
65 | 52 | cache_size_min = 3 |
@@ -75,36 +62,10 b' class DisplayHook(Configurable):' | |||
|
75 | 62 | self.do_full_cache = 1 |
|
76 | 63 | |
|
77 | 64 | self.cache_size = cache_size |
|
78 | self.input_sep = input_sep | |
|
79 | 65 | |
|
80 | 66 | # we need a reference to the user-level namespace |
|
81 | 67 | self.shell = shell |
|
82 | 68 | |
|
83 | # Set input prompt strings and colors | |
|
84 | if cache_size == 0: | |
|
85 | if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \ | |
|
86 | or ps1.find(r'\N') > -1: | |
|
87 | ps1 = '>>> ' | |
|
88 | if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \ | |
|
89 | or ps2.find(r'\N') > -1: | |
|
90 | ps2 = '... ' | |
|
91 | self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ') | |
|
92 | self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ') | |
|
93 | self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','') | |
|
94 | ||
|
95 | self.color_table = prompts.PromptColors | |
|
96 | self.prompt1 = prompts.Prompt1(self,sep=input_sep,prompt=self.ps1_str, | |
|
97 | pad_left=pad_left) | |
|
98 | self.prompt2 = prompts.Prompt2(self,prompt=self.ps2_str,pad_left=pad_left) | |
|
99 | self.prompt_out = prompts.PromptOut(self,sep='',prompt=self.ps_out_str, | |
|
100 | pad_left=pad_left) | |
|
101 | self.set_colors(colors) | |
|
102 | ||
|
103 | # Store the last prompt string each time, we need it for aligning | |
|
104 | # continuation and auto-rewrite prompts | |
|
105 | self.last_prompt = '' | |
|
106 | self.output_sep = output_sep | |
|
107 | self.output_sep2 = output_sep2 | |
|
108 | 69 | self._,self.__,self.___ = '','','' |
|
109 | 70 | |
|
110 | 71 | # these are deliberately global: |
@@ -115,32 +76,6 b' class DisplayHook(Configurable):' | |||
|
115 | 76 | def prompt_count(self): |
|
116 | 77 | return self.shell.execution_count |
|
117 | 78 | |
|
118 | def _set_prompt_str(self,p_str,cache_def,no_cache_def): | |
|
119 | if p_str is None: | |
|
120 | if self.do_full_cache: | |
|
121 | return cache_def | |
|
122 | else: | |
|
123 | return no_cache_def | |
|
124 | else: | |
|
125 | return p_str | |
|
126 | ||
|
127 | def set_colors(self, colors): | |
|
128 | """Set the active color scheme and configure colors for the three | |
|
129 | prompt subsystems.""" | |
|
130 | ||
|
131 | # FIXME: This modifying of the global prompts.prompt_specials needs | |
|
132 | # to be fixed. We need to refactor all of the prompts stuff to use | |
|
133 | # proper configuration and traits notifications. | |
|
134 | if colors.lower()=='nocolor': | |
|
135 | prompts.prompt_specials = prompts.prompt_specials_nocolor | |
|
136 | else: | |
|
137 | prompts.prompt_specials = prompts.prompt_specials_color | |
|
138 | ||
|
139 | self.color_table.set_active_scheme(colors) | |
|
140 | self.prompt1.set_colors() | |
|
141 | self.prompt2.set_colors() | |
|
142 | self.prompt_out.set_colors() | |
|
143 | ||
|
144 | 79 | #------------------------------------------------------------------------- |
|
145 | 80 | # Methods used in __call__. Override these methods to modify the behavior |
|
146 | 81 | # of the displayhook. |
@@ -180,8 +115,8 b' class DisplayHook(Configurable):' | |||
|
180 | 115 | ``io.stdout``. |
|
181 | 116 | """ |
|
182 | 117 | # Use write, not print which adds an extra space. |
|
183 |
io.stdout.write(self. |
|
|
184 |
outprompt = |
|
|
118 | io.stdout.write(self.shell.separate_out) | |
|
119 | outprompt = self.shell.prompt_manager.render('out') | |
|
185 | 120 | if self.do_full_cache: |
|
186 | 121 | io.stdout.write(outprompt) |
|
187 | 122 | |
@@ -235,11 +170,12 b' class DisplayHook(Configurable):' | |||
|
235 | 170 | # So that multi-line strings line up with the left column of |
|
236 | 171 | # the screen, instead of having the output prompt mess up |
|
237 | 172 | # their first line. |
|
238 |
# We use the p |
|
|
173 | # We use the prompt template instead of the expanded prompt | |
|
239 | 174 | # because the expansion may add ANSI escapes that will interfere |
|
240 | 175 | # with our ability to determine whether or not we should add |
|
241 | 176 | # a newline. |
|
242 | if self.ps_out_str and not self.ps_out_str.endswith('\n'): | |
|
177 | prompt_template = self.shell.prompt_manager.out_template | |
|
178 | if prompt_template and not prompt_template.endswith('\n'): | |
|
243 | 179 | # But avoid extraneous empty lines. |
|
244 | 180 | result_repr = '\n' + result_repr |
|
245 | 181 | |
@@ -286,7 +222,7 b' class DisplayHook(Configurable):' | |||
|
286 | 222 | |
|
287 | 223 | def finish_displayhook(self): |
|
288 | 224 | """Finish up all displayhook activities.""" |
|
289 |
io.stdout.write(self. |
|
|
225 | io.stdout.write(self.shell.separate_out2) | |
|
290 | 226 | io.stdout.flush() |
|
291 | 227 | |
|
292 | 228 | def __call__(self, result=None): |
@@ -63,6 +63,7 b' from IPython.core.plugin import PluginManager' | |||
|
63 | 63 | from IPython.core.prefilter import PrefilterManager, ESC_MAGIC |
|
64 | 64 | from IPython.core.profiledir import ProfileDir |
|
65 | 65 | from IPython.core.pylabtools import pylab_activate |
|
66 | from IPython.core.prompts import PromptManager | |
|
66 | 67 | from IPython.external.Itpl import ItplNS |
|
67 | 68 | from IPython.utils import PyColorize |
|
68 | 69 | from IPython.utils import io |
@@ -594,10 +595,7 b' class InteractiveShell(SingletonConfigurable, Magic):' | |||
|
594 | 595 | io.stderr = io.IOStream(sys.stderr) |
|
595 | 596 | |
|
596 | 597 | def init_prompts(self): |
|
597 | # TODO: This is a pass for now because the prompts are managed inside | |
|
598 | # the DisplayHook. Once there is a separate prompt manager, this | |
|
599 | # will initialize that object and all prompt related information. | |
|
600 | pass | |
|
598 | self.prompt_manager = PromptManager(shell=self, config=self.config) | |
|
601 | 599 | |
|
602 | 600 | def init_display_formatter(self): |
|
603 | 601 | self.display_formatter = DisplayFormatter(config=self.config) |
@@ -613,13 +611,6 b' class InteractiveShell(SingletonConfigurable, Magic):' | |||
|
613 | 611 | config=self.config, |
|
614 | 612 | shell=self, |
|
615 | 613 | cache_size=self.cache_size, |
|
616 | input_sep = self.separate_in, | |
|
617 | output_sep = self.separate_out, | |
|
618 | output_sep2 = self.separate_out2, | |
|
619 | ps1 = self.prompt_in1, | |
|
620 | ps2 = self.prompt_in2, | |
|
621 | ps_out = self.prompt_out, | |
|
622 | pad_left = self.prompts_pad_left | |
|
623 | 614 | ) |
|
624 | 615 | self.configurables.append(self.displayhook) |
|
625 | 616 | # This is a context manager that installs/revmoes the displayhook at |
@@ -2149,7 +2140,7 b' class InteractiveShell(SingletonConfigurable, Magic):' | |||
|
2149 | 2140 | after the user's input prompt. This helps the user understand that the |
|
2150 | 2141 | input line was transformed automatically by IPython. |
|
2151 | 2142 | """ |
|
2152 |
rw = self. |
|
|
2143 | rw = self.prompt_manager.render('rewrite') + cmd | |
|
2153 | 2144 | |
|
2154 | 2145 | try: |
|
2155 | 2146 | # plain ascii works better w/ pyreadline, on some machines, so |
@@ -2554,12 +2554,12 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
2554 | 2554 | |
|
2555 | 2555 | # Set prompt colors |
|
2556 | 2556 | try: |
|
2557 |
shell. |
|
|
2557 | shell.prompt_manager.color_scheme = new_scheme | |
|
2558 | 2558 | except: |
|
2559 | 2559 | color_switch_err('prompt') |
|
2560 | 2560 | else: |
|
2561 | 2561 | shell.colors = \ |
|
2562 |
|
|
|
2562 | shell.prompt_manager.color_scheme_table.active_scheme_name | |
|
2563 | 2563 | # Set exception colors |
|
2564 | 2564 | try: |
|
2565 | 2565 | shell.InteractiveTB.set_colors(scheme = new_scheme) |
@@ -3237,7 +3237,7 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
3237 | 3237 | |
|
3238 | 3238 | # Shorthands |
|
3239 | 3239 | shell = self.shell |
|
3240 |
|
|
|
3240 | pm = shell.prompt_manager | |
|
3241 | 3241 | meta = shell.meta |
|
3242 | 3242 | disp_formatter = self.shell.display_formatter |
|
3243 | 3243 | ptformatter = disp_formatter.formatters['text/plain'] |
@@ -3252,23 +3252,23 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
3252 | 3252 | save_dstore('xmode',shell.InteractiveTB.mode) |
|
3253 | 3253 | save_dstore('rc_separate_out',shell.separate_out) |
|
3254 | 3254 | save_dstore('rc_separate_out2',shell.separate_out2) |
|
3255 |
save_dstore('rc_prompts_pad_left', |
|
|
3255 | save_dstore('rc_prompts_pad_left',pm.justify) | |
|
3256 | 3256 | save_dstore('rc_separate_in',shell.separate_in) |
|
3257 | 3257 | save_dstore('rc_plain_text_only',disp_formatter.plain_text_only) |
|
3258 | save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template)) | |
|
3258 | 3259 | |
|
3259 | 3260 | if mode == False: |
|
3260 | 3261 | # turn on |
|
3261 |
|
|
|
3262 |
|
|
|
3263 |
|
|
|
3262 | pm.in_template = '>>> ' | |
|
3263 | pm.in2_template = '... ' | |
|
3264 | pm.out_template = '' | |
|
3264 | 3265 | |
|
3265 | 3266 | # Prompt separators like plain python |
|
3266 | oc.input_sep = oc.prompt1.sep = '' | |
|
3267 |
|
|
|
3268 |
|
|
|
3267 | shell.separate_in = '' | |
|
3268 | shell.separate_out = '' | |
|
3269 | shell.separate_out2 = '' | |
|
3269 | 3270 | |
|
3270 | oc.prompt1.pad_left = oc.prompt2.pad_left = \ | |
|
3271 | oc.prompt_out.pad_left = False | |
|
3271 | pm.justify = False | |
|
3272 | 3272 | |
|
3273 | 3273 | ptformatter.pprint = False |
|
3274 | 3274 | disp_formatter.plain_text_only = True |
@@ -3276,17 +3276,14 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
3276 | 3276 | shell.magic_xmode('Plain') |
|
3277 | 3277 | else: |
|
3278 | 3278 | # turn off |
|
3279 | oc.prompt1.p_template = shell.prompt_in1 | |
|
3280 | oc.prompt2.p_template = shell.prompt_in2 | |
|
3281 | oc.prompt_out.p_template = shell.prompt_out | |
|
3279 | pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates | |
|
3282 | 3280 | |
|
3283 |
|
|
|
3281 | shell.separate_in = dstore.rc_separate_in | |
|
3284 | 3282 | |
|
3285 |
|
|
|
3286 |
|
|
|
3283 | shell.separate_out = dstore.rc_separate_out | |
|
3284 | shell.separate_out2 = dstore.rc_separate_out2 | |
|
3287 | 3285 | |
|
3288 | oc.prompt1.pad_left = oc.prompt2.pad_left = \ | |
|
3289 | oc.prompt_out.pad_left = dstore.rc_prompts_pad_left | |
|
3286 | pm.justify = dstore.rc_prompts_pad_left | |
|
3290 | 3287 | |
|
3291 | 3288 | ptformatter.pprint = dstore.rc_pprint |
|
3292 | 3289 | disp_formatter.plain_text_only = dstore.rc_plain_text_only |
@@ -23,20 +23,23 b' import os' | |||
|
23 | 23 | import re |
|
24 | 24 | import socket |
|
25 | 25 | import sys |
|
26 | import time | |
|
26 | 27 | |
|
28 | from IPython.config.configurable import Configurable | |
|
27 | 29 | from IPython.core import release |
|
28 | from IPython.external.Itpl import ItplNS | |
|
29 | 30 | from IPython.utils import coloransi |
|
31 | from IPython.utils.traitlets import (Unicode, Instance, Dict, Bool, Int) | |
|
30 | 32 | |
|
31 | 33 | #----------------------------------------------------------------------------- |
|
32 | 34 | # Color schemes for prompts |
|
33 | 35 | #----------------------------------------------------------------------------- |
|
34 | 36 | |
|
35 | PromptColors = coloransi.ColorSchemeTable() | |
|
36 | 37 | InputColors = coloransi.InputTermColors # just a shorthand |
|
37 | 38 | Colors = coloransi.TermColors # just a shorthand |
|
38 | 39 | |
|
39 | PromptColors.add_scheme(coloransi.ColorScheme( | |
|
40 | color_lists = dict(normal=Colors(), inp=InputColors(), nocolor=coloransi.NoColors()) | |
|
41 | ||
|
42 | PColNoColors = coloransi.ColorScheme( | |
|
40 | 43 | 'NoColor', |
|
41 | 44 | in_prompt = InputColors.NoColor, # Input prompt |
|
42 | 45 | in_number = InputColors.NoColor, # Input prompt number |
@@ -47,10 +50,10 b' PromptColors.add_scheme(coloransi.ColorScheme(' | |||
|
47 | 50 | out_number = Colors.NoColor, # Output prompt number |
|
48 | 51 | |
|
49 | 52 | normal = Colors.NoColor # color off (usu. Colors.Normal) |
|
50 |
) |
|
|
53 | ) | |
|
51 | 54 | |
|
52 | 55 | # make some schemes as instances so we can copy them for modification easily: |
|
53 |
|
|
|
56 | PColLinux = coloransi.ColorScheme( | |
|
54 | 57 | 'Linux', |
|
55 | 58 | in_prompt = InputColors.Green, |
|
56 | 59 | in_number = InputColors.LightGreen, |
@@ -62,25 +65,35 b' __PColLinux = coloransi.ColorScheme(' | |||
|
62 | 65 | |
|
63 | 66 | normal = Colors.Normal |
|
64 | 67 | ) |
|
65 | # Don't forget to enter it into the table! | |
|
66 | PromptColors.add_scheme(__PColLinux) | |
|
67 | 68 | |
|
68 | 69 | # Slightly modified Linux for light backgrounds |
|
69 |
|
|
|
70 | PColLightBG = PColLinux.copy('LightBG') | |
|
70 | 71 | |
|
71 |
|
|
|
72 | PColLightBG.colors.update( | |
|
72 | 73 | in_prompt = InputColors.Blue, |
|
73 | 74 | in_number = InputColors.LightBlue, |
|
74 | 75 | in_prompt2 = InputColors.Blue |
|
75 | 76 | ) |
|
76 | PromptColors.add_scheme(__PColLightBG) | |
|
77 | ||
|
78 | del Colors,InputColors | |
|
79 | 77 | |
|
80 | 78 | #----------------------------------------------------------------------------- |
|
81 | 79 | # Utilities |
|
82 | 80 | #----------------------------------------------------------------------------- |
|
83 | 81 | |
|
82 | class LazyEvaluate(object): | |
|
83 | """This is used for formatting strings with values that need to be updated | |
|
84 | at that time, such as the current time or line number.""" | |
|
85 | def __init__(self, func, *args, **kwargs): | |
|
86 | self.func = func | |
|
87 | self.args = args | |
|
88 | self.kwargs = kwargs | |
|
89 | ||
|
90 | def __call__(self, **kwargs): | |
|
91 | self.kwargs.update(kwargs) | |
|
92 | return self.func(*self.args, **self.kwargs) | |
|
93 | ||
|
94 | def __str__(self): | |
|
95 | return str(self()) | |
|
96 | ||
|
84 | 97 | def multiple_replace(dict, text): |
|
85 | 98 | """ Replace in 'text' all occurences of any key in the given |
|
86 | 99 | dictionary by its corresponding value. Returns the new string.""" |
@@ -121,51 +134,43 b' HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")' | |||
|
121 | 134 | USER = os.environ.get("USER") |
|
122 | 135 | HOSTNAME = socket.gethostname() |
|
123 | 136 | HOSTNAME_SHORT = HOSTNAME.split(".")[0] |
|
124 |
ROOT_SYMBOL = " |
|
|
137 | ROOT_SYMBOL = "#" if (os.name=='nt' or os.getuid()==0) else "$" | |
|
125 | 138 | |
|
126 |
prompt_ |
|
|
139 | prompt_abbreviations = { | |
|
127 | 140 | # Prompt/history count |
|
128 |
'%n' : ' |
|
|
129 |
r'\#': ' |
|
|
141 | '%n' : '{color.number}' '{count}' '{color.prompt}', | |
|
142 | r'\#': '{color.number}' '{count}' '{color.prompt}', | |
|
130 | 143 | # Just the prompt counter number, WITHOUT any coloring wrappers, so users |
|
131 | 144 | # can get numbers displayed in whatever color they want. |
|
132 |
r'\N': ' |
|
|
145 | r'\N': '{count}', | |
|
133 | 146 | |
|
134 | 147 | # Prompt/history count, with the actual digits replaced by dots. Used |
|
135 | 148 | # mainly in continuation prompts (prompt_in2) |
|
136 | #r'\D': '${"."*len(str(self.cache.prompt_count))}', | |
|
137 | ||
|
138 | # More robust form of the above expression, that uses the __builtin__ | |
|
139 | # module. Note that we can NOT use __builtins__ (note the 's'), because | |
|
140 | # that can either be a dict or a module, and can even mutate at runtime, | |
|
141 | # depending on the context (Python makes no guarantees on it). In | |
|
142 | # contrast, __builtin__ is always a module object, though it must be | |
|
143 | # explicitly imported. | |
|
144 | r'\D': '${"."*__builtin__.len(__builtin__.str(self.cache.prompt_count))}', | |
|
149 | r'\D': '{dots}', | |
|
145 | 150 | |
|
146 | # Current working directory | |
|
147 | r'\w': '${os.getcwd()}', | |
|
148 | 151 | # Current time |
|
149 |
r'\t' : ' |
|
|
152 | r'\t' : '{time}', | |
|
153 | # Current working directory | |
|
154 | r'\w': '{cwd}', | |
|
150 | 155 | # Basename of current working directory. |
|
151 | 156 | # (use os.sep to make this portable across OSes) |
|
152 | r'\W' : '${os.getcwd().split("%s")[-1]}' % os.sep, | |
|
157 | r'\W' : '{cwd_last}', | |
|
153 | 158 | # These X<N> are an extension to the normal bash prompts. They return |
|
154 | 159 | # N terms of the path, after replacing $HOME with '~' |
|
155 | r'\X0': '${os.getcwd().replace("%s","~")}' % HOME, | |
|
156 |
r'\X1': ' |
|
|
157 |
r'\X2': ' |
|
|
158 |
r'\X3': ' |
|
|
159 |
r'\X4': ' |
|
|
160 |
r'\X5': ' |
|
|
160 | r'\X0': '{cwd_x[0])}', | |
|
161 | r'\X1': '{cwd_x[1])}', | |
|
162 | r'\X2': '{cwd_x[2])}', | |
|
163 | r'\X3': '{cwd_x[3])}', | |
|
164 | r'\X4': '{cwd_x[4])}', | |
|
165 | r'\X5': '{cwd_x[5])}', | |
|
161 | 166 | # Y<N> are similar to X<N>, but they show '~' if it's the directory |
|
162 | 167 | # N+1 in the list. Somewhat like %cN in tcsh. |
|
163 |
r'\Y0': ' |
|
|
164 |
r'\Y1': ' |
|
|
165 |
r'\Y2': ' |
|
|
166 |
r'\Y3': ' |
|
|
167 |
r'\Y4': ' |
|
|
168 |
r'\Y5': ' |
|
|
168 | r'\Y0': '{cwd_y[0])}', | |
|
169 | r'\Y1': '{cwd_y[1])}', | |
|
170 | r'\Y2': '{cwd_y[2])}', | |
|
171 | r'\Y3': '{cwd_y[3])}', | |
|
172 | r'\Y4': '{cwd_y[4])}', | |
|
173 | r'\Y5': '{cwd_y[5])}', | |
|
169 | 174 | # Hostname up to first . |
|
170 | 175 | r'\h': HOSTNAME_SHORT, |
|
171 | 176 | # Full hostname |
@@ -184,28 +189,6 b' prompt_specials_color = {' | |||
|
184 | 189 | r'\$': ROOT_SYMBOL, |
|
185 | 190 | } |
|
186 | 191 | |
|
187 | # A copy of the prompt_specials dictionary but with all color escapes removed, | |
|
188 | # so we can correctly compute the prompt length for the auto_rewrite method. | |
|
189 | prompt_specials_nocolor = prompt_specials_color.copy() | |
|
190 | prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}' | |
|
191 | prompt_specials_nocolor[r'\#'] = '${self.cache.prompt_count}' | |
|
192 | ||
|
193 | # Add in all the InputTermColors color escapes as valid prompt characters. | |
|
194 | # They all get added as \\C_COLORNAME, so that we don't have any conflicts | |
|
195 | # with a color name which may begin with a letter used by any other of the | |
|
196 | # allowed specials. This of course means that \\C will never be allowed for | |
|
197 | # anything else. | |
|
198 | input_colors = coloransi.InputTermColors | |
|
199 | for _color in dir(input_colors): | |
|
200 | if _color[0] != '_': | |
|
201 | c_name = r'\C_'+_color | |
|
202 | prompt_specials_color[c_name] = getattr(input_colors,_color) | |
|
203 | prompt_specials_nocolor[c_name] = '' | |
|
204 | ||
|
205 | # we default to no color for safety. Note that prompt_specials is a global | |
|
206 | # variable used by all prompt objects. | |
|
207 | prompt_specials = prompt_specials_nocolor | |
|
208 | ||
|
209 | 192 | #----------------------------------------------------------------------------- |
|
210 | 193 | # More utilities |
|
211 | 194 | #----------------------------------------------------------------------------- |
@@ -230,90 +213,6 b' def str_safe(arg):' | |||
|
230 | 213 | #raise # dbg |
|
231 | 214 | return out |
|
232 | 215 | |
|
233 | #----------------------------------------------------------------------------- | |
|
234 | # Prompt classes | |
|
235 | #----------------------------------------------------------------------------- | |
|
236 | ||
|
237 | class BasePrompt(object): | |
|
238 | """Interactive prompt similar to Mathematica's.""" | |
|
239 | ||
|
240 | def _get_p_template(self): | |
|
241 | return self._p_template | |
|
242 | ||
|
243 | def _set_p_template(self,val): | |
|
244 | self._p_template = val | |
|
245 | self.set_p_str() | |
|
246 | ||
|
247 | p_template = property(_get_p_template,_set_p_template, | |
|
248 | doc='Template for prompt string creation') | |
|
249 | ||
|
250 | def __init__(self, cache, sep, prompt, pad_left=False): | |
|
251 | ||
|
252 | # Hack: we access information about the primary prompt through the | |
|
253 | # cache argument. We need this, because we want the secondary prompt | |
|
254 | # to be aligned with the primary one. Color table info is also shared | |
|
255 | # by all prompt classes through the cache. Nice OO spaghetti code! | |
|
256 | self.cache = cache | |
|
257 | self.sep = sep | |
|
258 | ||
|
259 | # regexp to count the number of spaces at the end of a prompt | |
|
260 | # expression, useful for prompt auto-rewriting | |
|
261 | self.rspace = re.compile(r'(\s*)$') | |
|
262 | # Flag to left-pad prompt strings to match the length of the primary | |
|
263 | # prompt | |
|
264 | self.pad_left = pad_left | |
|
265 | ||
|
266 | # Set template to create each actual prompt (where numbers change). | |
|
267 | # Use a property | |
|
268 | self.p_template = prompt | |
|
269 | self.set_p_str() | |
|
270 | ||
|
271 | def set_p_str(self): | |
|
272 | """ Set the interpolating prompt strings. | |
|
273 | ||
|
274 | This must be called every time the color settings change, because the | |
|
275 | prompt_specials global may have changed.""" | |
|
276 | ||
|
277 | import os,time # needed in locals for prompt string handling | |
|
278 | loc = locals() | |
|
279 | try: | |
|
280 | self.p_str = ItplNS('%s%s%s' % | |
|
281 | ('${self.sep}${self.col_p}', | |
|
282 | multiple_replace(prompt_specials, self.p_template), | |
|
283 | '${self.col_norm}'),self.cache.shell.user_ns,loc) | |
|
284 | ||
|
285 | self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor, | |
|
286 | self.p_template), | |
|
287 | self.cache.shell.user_ns,loc) | |
|
288 | except: | |
|
289 | print "Illegal prompt template (check $ usage!):",self.p_template | |
|
290 | self.p_str = self.p_template | |
|
291 | self.p_str_nocolor = self.p_template | |
|
292 | ||
|
293 | def write(self, msg): | |
|
294 | sys.stdout.write(msg) | |
|
295 | return '' | |
|
296 | ||
|
297 | def __str__(self): | |
|
298 | """Return a string form of the prompt. | |
|
299 | ||
|
300 | This for is useful for continuation and output prompts, since it is | |
|
301 | left-padded to match lengths with the primary one (if the | |
|
302 | self.pad_left attribute is set).""" | |
|
303 | ||
|
304 | out_str = str_safe(self.p_str) | |
|
305 | if self.pad_left: | |
|
306 | # We must find the amount of padding required to match lengths, | |
|
307 | # taking the color escapes (which are invisible on-screen) into | |
|
308 | # account. | |
|
309 | esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor)) | |
|
310 | format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad) | |
|
311 | return format % out_str | |
|
312 | else: | |
|
313 | return out_str | |
|
314 | ||
|
315 | # these path filters are put in as methods so that we can control the | |
|
316 | # namespace where the prompt strings get evaluated | |
|
317 | 216 |
|
|
318 | 217 |
|
|
319 | 218 | |
@@ -322,10 +221,7 b' class BasePrompt(object):' | |||
|
322 | 221 | |
|
323 | 222 |
|
|
324 | 223 |
|
|
325 | if out: | |
|
326 | return out | |
|
327 | else: | |
|
328 | return os.sep | |
|
224 | return out or os.sep | |
|
329 | 225 | |
|
330 | 226 |
|
|
331 | 227 |
|
@@ -342,95 +238,141 b' class BasePrompt(object):' | |||
|
342 | 238 |
|
|
343 | 239 |
|
|
344 | 240 | |
|
345 | if out: | |
|
346 | return out | |
|
347 | else: | |
|
348 | return os.sep | |
|
349 | ||
|
350 | def __nonzero__(self): | |
|
351 | """Implement boolean behavior. | |
|
352 | ||
|
353 | Checks whether the p_str attribute is non-empty""" | |
|
241 | return out or os.sep | |
|
354 | 242 | |
|
355 | return bool(self.p_template) | |
|
356 | ||
|
357 | ||
|
358 | class Prompt1(BasePrompt): | |
|
359 | """Input interactive prompt similar to Mathematica's.""" | |
|
243 | #----------------------------------------------------------------------------- | |
|
244 | # Prompt classes | |
|
245 | #----------------------------------------------------------------------------- | |
|
360 | 246 | |
|
361 | def __init__(self, cache, sep='\n', prompt='In [\\#]: ', pad_left=True): | |
|
362 | BasePrompt.__init__(self, cache, sep, prompt, pad_left) | |
|
247 | lazily_evaluate = {'time': LazyEvaluate(time.strftime, "%H:%M:%S"), | |
|
248 | 'cwd': LazyEvaluate(os.getcwd), | |
|
249 | 'cwd_last': LazyEvaluate(lambda: os.getcwd().split(os.sep)[-1]), | |
|
250 | 'cwd_x': [LazyEvaluate(lambda: os.getcwd().replace("%s","~"))] +\ | |
|
251 | [LazyEvaluate(cwd_filt, x) for x in range(1,6)], | |
|
252 | 'cwd_y': [LazyEvaluate(cwd_filt2, x) for x in range(6)] | |
|
253 | } | |
|
363 | 254 | |
|
364 | def set_colors(self): | |
|
365 | self.set_p_str() | |
|
366 | Colors = self.cache.color_table.active_colors # shorthand | |
|
367 | self.col_p = Colors.in_prompt | |
|
368 | self.col_num = Colors.in_number | |
|
369 | self.col_norm = Colors.in_normal | |
|
370 | # We need a non-input version of these escapes for the '--->' | |
|
371 | # auto-call prompts used in the auto_rewrite() method. | |
|
372 | self.col_p_ni = self.col_p.replace('\001','').replace('\002','') | |
|
373 | self.col_norm_ni = Colors.normal | |
|
374 | 255 | |
|
375 | def __str__(self): | |
|
376 | self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1] | |
|
377 | return str_safe(self.p_str) | |
|
378 | ||
|
379 | def auto_rewrite(self): | |
|
380 | """Return a string of the form '--->' which lines up with the previous | |
|
381 | input string. Useful for systems which re-write the user input when | |
|
382 | handling automatically special syntaxes.""" | |
|
383 | ||
|
384 |
|
|
|
385 | nrspaces = len(self.rspace.search(curr).group()) | |
|
386 | return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1), | |
|
387 | ' '*nrspaces,self.col_norm_ni) | |
|
388 | ||
|
389 | ||
|
390 | class PromptOut(BasePrompt): | |
|
391 | """Output interactive prompt similar to Mathematica's.""" | |
|
392 | ||
|
393 | def __init__(self, cache, sep='', prompt='Out[\\#]: ', pad_left=True): | |
|
394 | BasePrompt.__init__(self, cache, sep, prompt, pad_left) | |
|
395 | if not self.p_template: | |
|
396 | self.__str__ = lambda: '' | |
|
397 | ||
|
398 | def set_colors(self): | |
|
399 | self.set_p_str() | |
|
400 | Colors = self.cache.color_table.active_colors # shorthand | |
|
401 | self.col_p = Colors.out_prompt | |
|
402 | self.col_num = Colors.out_number | |
|
403 | self.col_norm = Colors.normal | |
|
404 | ||
|
405 | ||
|
406 | class Prompt2(BasePrompt): | |
|
407 | """Interactive continuation prompt.""" | |
|
408 | ||
|
409 | def __init__(self, cache, prompt=' .\\D.: ', pad_left=True): | |
|
410 | self.cache = cache | |
|
411 | self.p_template = prompt | |
|
412 | self.pad_left = pad_left | |
|
413 | self.set_p_str() | |
|
414 | ||
|
415 | def set_p_str(self): | |
|
416 | import os,time # needed in locals for prompt string handling | |
|
417 | loc = locals() | |
|
418 | self.p_str = ItplNS('%s%s%s' % | |
|
419 | ('${self.col_p2}', | |
|
420 | multiple_replace(prompt_specials, self.p_template), | |
|
421 | '$self.col_norm'), | |
|
422 | self.cache.shell.user_ns,loc) | |
|
423 | self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor, | |
|
424 | self.p_template), | |
|
425 | self.cache.shell.user_ns,loc) | |
|
426 | ||
|
427 | def set_colors(self): | |
|
428 | self.set_p_str() | |
|
429 | Colors = self.cache.color_table.active_colors | |
|
430 | self.col_p2 = Colors.in_prompt2 | |
|
431 | self.col_norm = Colors.in_normal | |
|
432 | # FIXME (2004-06-16) HACK: prevent crashes for users who haven't | |
|
433 | # updated their prompt_in2 definitions. Remove eventually. | |
|
434 | self.col_p = Colors.out_prompt | |
|
435 | self.col_num = Colors.out_number | |
|
256 | class PromptManager(Configurable): | |
|
257 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | |
|
258 | ||
|
259 | color_scheme_table = Instance(coloransi.ColorSchemeTable) | |
|
260 | color_scheme = Unicode('Linux') | |
|
261 | def _color_scheme_changed(self, name, new_value): | |
|
262 | self.color_scheme_table.set_active_scheme(new_value) | |
|
263 | for pname in ['in', 'in2', 'out', 'rewrite']: | |
|
264 | # We need to recalculate the number of invisible characters | |
|
265 | self.update_prompt(pname) | |
|
266 | ||
|
267 | # These fields can be referenced in prompt templates, and are evaluated | |
|
268 | # when the prompt is generated - for things like timestamps. They are only | |
|
269 | # evaluated if a prompt uses them. | |
|
270 | lazy_evaluate_fields = Dict() | |
|
271 | def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy() | |
|
272 | ||
|
273 | in_template = Unicode('In [\\#]: ', config=True) | |
|
274 | in2_template = Unicode(' .\\D.: ', config=True) | |
|
275 | out_template = Unicode('Out[\\#]: ', config=True) | |
|
276 | rewrite_template = Unicode("------> ", config=True) | |
|
277 | ||
|
278 | # Justify prompts by default? | |
|
279 | justify = Bool(True) | |
|
280 | ||
|
281 | # We actually store the expanded templates here: | |
|
282 | templates = Dict() | |
|
283 | ||
|
284 | # The number of characters in the last prompt rendered, not including | |
|
285 | # colour characters. | |
|
286 | width = Int() | |
|
287 | ||
|
288 | # The number of characters in each prompt which don't contribute to width | |
|
289 | invisible_chars = Dict() | |
|
290 | def _invisible_chars_default(self): | |
|
291 | return {'in': 0, 'in2': 0, 'out': 0, 'rewrite': 0} | |
|
292 | ||
|
293 | def __init__(self, shell, config=None): | |
|
294 | super(PromptManager, self).__init__(shell=shell, config=config) | |
|
295 | ||
|
296 | # Prepare colour scheme table | |
|
297 | self.color_scheme_table = coloransi.ColorSchemeTable([PColNoColors, | |
|
298 | PColLinux, PColLightBG], self.color_scheme) | |
|
299 | ||
|
300 | # Prepare templates | |
|
301 | self.update_prompt('in', self.in_template) | |
|
302 | self.update_prompt('in2', self.in2_template) | |
|
303 | self.update_prompt('out', self.out_template) | |
|
304 | self.update_prompt('rewrite', self.rewrite_template) | |
|
305 | self.on_trait_change(self._update_prompt_trait, ['in_template', | |
|
306 | 'in2_template', 'out_template', 'rewrite_template']) | |
|
307 | ||
|
308 | def update_prompt(self, name, new_template=None): | |
|
309 | if new_template is not None: | |
|
310 | self.templates[name] = multiple_replace(prompt_abbreviations, new_template) | |
|
311 | invis_chars = len(self.render(name, color=True, just=False)) - \ | |
|
312 | len(self.render(name, color=False, just=False)) | |
|
313 | self.invisible_chars[name] = invis_chars | |
|
314 | ||
|
315 | def _update_prompt_trait(self, traitname, new_template): | |
|
316 | name = traitname[:-9] # Cut off '_template' | |
|
317 | self.update_prompt(name, new_template) | |
|
318 | ||
|
319 | def render(self, name, color=True, just=None, **kwargs): | |
|
320 | """ | |
|
321 | Render the selected prompt. | |
|
322 | ||
|
323 | Parameters | |
|
324 | ---------- | |
|
325 | name : str | |
|
326 | Which prompt to render. One of 'in', 'in2', 'out', 'rewrite' | |
|
327 | color : bool | |
|
328 | If True (default), include ANSI escape sequences for a coloured prompt. | |
|
329 | just : bool | |
|
330 | If True, justify the prompt to the width of the last prompt. The | |
|
331 | default is stored in self.justify. | |
|
332 | **kwargs : | |
|
333 | Additional arguments will be passed to the string formatting operation, | |
|
334 | so they can override the values that would otherwise fill in the | |
|
335 | template. | |
|
336 | ||
|
337 | Returns | |
|
338 | ------- | |
|
339 | A string containing the rendered prompt. | |
|
340 | """ | |
|
341 | if color: | |
|
342 | scheme = self.color_scheme_table.active_colors | |
|
343 | if name=='out': | |
|
344 | colors = color_lists['normal'] | |
|
345 | colors.number, colors.prompt, colors.normal = \ | |
|
346 | scheme.out_number, scheme.out_prompt, scheme.normal | |
|
347 | else: | |
|
348 | colors = color_lists['inp'] | |
|
349 | colors.number, colors.prompt, colors.normal = \ | |
|
350 | scheme.in_number, scheme.in_prompt, scheme.in_normal | |
|
351 | if name=='in2': | |
|
352 | colors.prompt = scheme.in_prompt2 | |
|
353 | else: | |
|
354 | # No color | |
|
355 | colors = color_lists['nocolor'] | |
|
356 | colors.number, colors.prompt, colors.normal = '', '', '' | |
|
357 | ||
|
358 | count = self.shell.execution_count # Shorthand | |
|
359 | # Build the dictionary to be passed to string formatting | |
|
360 | fmtargs = dict(color=colors, count=count, | |
|
361 | dots="."*len(str(count)) ) | |
|
362 | fmtargs.update(self.lazy_evaluate_fields) | |
|
363 | fmtargs.update(kwargs) | |
|
364 | ||
|
365 | # Prepare the prompt | |
|
366 | prompt = colors.prompt + self.templates[name] + colors.normal | |
|
367 | ||
|
368 | # Fill in required fields | |
|
369 | res = prompt.format(**fmtargs) | |
|
370 | ||
|
371 | # Handle justification of prompt | |
|
372 | invis_chars = self.invisible_chars[name] if color else 0 | |
|
373 | just = self.justify if (just is None) else just | |
|
374 | if just: | |
|
375 | res = res.rjust(self.width + invis_chars) | |
|
376 | self.width = len(res) - invis_chars | |
|
377 | return res | |
|
436 | 378 |
@@ -148,7 +148,7 b' class TestMagicRunPass(tt.TempFileMixin):' | |||
|
148 | 148 | """Test that prompts correctly generate after %run""" |
|
149 | 149 | self.run_tmpfile() |
|
150 | 150 | _ip = get_ipython() |
|
151 |
p2 = |
|
|
151 | p2 = _ip.prompt_manager.render('in2').strip() | |
|
152 | 152 | nt.assert_equals(p2[:3], '...') |
|
153 | 153 | |
|
154 | 154 | def test_run_profile( self ): |
@@ -356,7 +356,7 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
356 | 356 | self.hooks.pre_prompt_hook() |
|
357 | 357 | if more: |
|
358 | 358 | try: |
|
359 |
prompt = self. |
|
|
359 | prompt = self.prompt_manager.render('in2') | |
|
360 | 360 | except: |
|
361 | 361 | self.showtraceback() |
|
362 | 362 | if self.autoindent: |
@@ -364,7 +364,7 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
364 | 364 | |
|
365 | 365 | else: |
|
366 | 366 | try: |
|
367 |
prompt = self. |
|
|
367 | prompt = self.separate_in + self.prompt_manager.render('in') | |
|
368 | 368 | except: |
|
369 | 369 | self.showtraceback() |
|
370 | 370 | try: |
@@ -15,11 +15,6 b' import os' | |||
|
15 | 15 | |
|
16 | 16 | from IPython.utils.ipstruct import Struct |
|
17 | 17 | |
|
18 | def make_color_table(in_class): | |
|
19 | """Build a set of color attributes in a class. | |
|
20 | ||
|
21 | Helper function for building the *TermColors classes.""" | |
|
22 | ||
|
23 | 18 |
|
|
24 | 19 | # Dark colors |
|
25 | 20 | ("Black" , "0;30"), |
@@ -50,6 +45,11 b' def make_color_table(in_class):' | |||
|
50 | 45 | ("BlinkLightGray", "5;37"), |
|
51 | 46 | ) |
|
52 | 47 | |
|
48 | def make_color_table(in_class): | |
|
49 | """Build a set of color attributes in a class. | |
|
50 | ||
|
51 | Helper function for building the *TermColors classes.""" | |
|
52 | ||
|
53 | 53 | for name,value in color_templates: |
|
54 | 54 | setattr(in_class,name,in_class._base % value) |
|
55 | 55 | |
@@ -98,6 +98,14 b' class InputTermColors:' | |||
|
98 | 98 | # Build the actual color table as a set of class attributes: |
|
99 | 99 | make_color_table(InputTermColors) |
|
100 | 100 | |
|
101 | class NoColors: | |
|
102 | """This defines all the same names as the colour classes, but maps them to | |
|
103 | empty strings, so it can easily be substituted to turn off colours.""" | |
|
104 | NoColor = '' | |
|
105 | ||
|
106 | for name, value in color_templates: | |
|
107 | setattr(NoColors, name, '') | |
|
108 | ||
|
101 | 109 | class ColorScheme: |
|
102 | 110 | """Generic color scheme class. Just a name and a Struct.""" |
|
103 | 111 | def __init__(self,__scheme_name_,colordict=None,**colormap): |
@@ -133,7 +133,7 b' class ZMQInteractiveShell(InteractiveShell):' | |||
|
133 | 133 | FIXME: this payload is currently not correctly processed by the |
|
134 | 134 | frontend. |
|
135 | 135 | """ |
|
136 |
new = self. |
|
|
136 | new = self.prompt_manager.render('rewrite') + cmd | |
|
137 | 137 | payload = dict( |
|
138 | 138 | source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input', |
|
139 | 139 | transformed_input=new, |
General Comments 0
You need to be logged in to leave comments.
Login now