##// END OF EJS Templates
Macros are now simple callables, no special handling in Prompt.py
vivainio -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,595 +1,588 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Classes for handling input/output prompts.
3 Classes for handling input/output prompts.
4
4
5 $Id: Prompts.py 2192 2007-04-01 20:51:06Z fperez $"""
5 $Id: Prompts.py 2349 2007-05-15 16:20:35Z vivainio $"""
6
6
7 #*****************************************************************************
7 #*****************************************************************************
8 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
8 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #*****************************************************************************
12 #*****************************************************************************
13
13
14 from IPython import Release
14 from IPython import Release
15 __author__ = '%s <%s>' % Release.authors['Fernando']
15 __author__ = '%s <%s>' % Release.authors['Fernando']
16 __license__ = Release.license
16 __license__ = Release.license
17 __version__ = Release.version
17 __version__ = Release.version
18
18
19 #****************************************************************************
19 #****************************************************************************
20 # Required modules
20 # Required modules
21 import __builtin__
21 import __builtin__
22 import os
22 import os
23 import socket
23 import socket
24 import sys
24 import sys
25 import time
25 import time
26
26
27 # IPython's own
27 # IPython's own
28 from IPython import ColorANSI
28 from IPython import ColorANSI
29 from IPython.Itpl import ItplNS
29 from IPython.Itpl import ItplNS
30 from IPython.ipstruct import Struct
30 from IPython.ipstruct import Struct
31 from IPython.macro import Macro
31 from IPython.macro import Macro
32 from IPython.genutils import *
32 from IPython.genutils import *
33
33
34 #****************************************************************************
34 #****************************************************************************
35 #Color schemes for Prompts.
35 #Color schemes for Prompts.
36
36
37 PromptColors = ColorANSI.ColorSchemeTable()
37 PromptColors = ColorANSI.ColorSchemeTable()
38 InputColors = ColorANSI.InputTermColors # just a shorthand
38 InputColors = ColorANSI.InputTermColors # just a shorthand
39 Colors = ColorANSI.TermColors # just a shorthand
39 Colors = ColorANSI.TermColors # just a shorthand
40
40
41 PromptColors.add_scheme(ColorANSI.ColorScheme(
41 PromptColors.add_scheme(ColorANSI.ColorScheme(
42 'NoColor',
42 'NoColor',
43 in_prompt = InputColors.NoColor, # Input prompt
43 in_prompt = InputColors.NoColor, # Input prompt
44 in_number = InputColors.NoColor, # Input prompt number
44 in_number = InputColors.NoColor, # Input prompt number
45 in_prompt2 = InputColors.NoColor, # Continuation prompt
45 in_prompt2 = InputColors.NoColor, # Continuation prompt
46 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
46 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
47
47
48 out_prompt = Colors.NoColor, # Output prompt
48 out_prompt = Colors.NoColor, # Output prompt
49 out_number = Colors.NoColor, # Output prompt number
49 out_number = Colors.NoColor, # Output prompt number
50
50
51 normal = Colors.NoColor # color off (usu. Colors.Normal)
51 normal = Colors.NoColor # color off (usu. Colors.Normal)
52 ))
52 ))
53
53
54 # make some schemes as instances so we can copy them for modification easily:
54 # make some schemes as instances so we can copy them for modification easily:
55 __PColLinux = ColorANSI.ColorScheme(
55 __PColLinux = ColorANSI.ColorScheme(
56 'Linux',
56 'Linux',
57 in_prompt = InputColors.Green,
57 in_prompt = InputColors.Green,
58 in_number = InputColors.LightGreen,
58 in_number = InputColors.LightGreen,
59 in_prompt2 = InputColors.Green,
59 in_prompt2 = InputColors.Green,
60 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
60 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
61
61
62 out_prompt = Colors.Red,
62 out_prompt = Colors.Red,
63 out_number = Colors.LightRed,
63 out_number = Colors.LightRed,
64
64
65 normal = Colors.Normal
65 normal = Colors.Normal
66 )
66 )
67 # Don't forget to enter it into the table!
67 # Don't forget to enter it into the table!
68 PromptColors.add_scheme(__PColLinux)
68 PromptColors.add_scheme(__PColLinux)
69
69
70 # Slightly modified Linux for light backgrounds
70 # Slightly modified Linux for light backgrounds
71 __PColLightBG = __PColLinux.copy('LightBG')
71 __PColLightBG = __PColLinux.copy('LightBG')
72
72
73 __PColLightBG.colors.update(
73 __PColLightBG.colors.update(
74 in_prompt = InputColors.Blue,
74 in_prompt = InputColors.Blue,
75 in_number = InputColors.LightBlue,
75 in_number = InputColors.LightBlue,
76 in_prompt2 = InputColors.Blue
76 in_prompt2 = InputColors.Blue
77 )
77 )
78 PromptColors.add_scheme(__PColLightBG)
78 PromptColors.add_scheme(__PColLightBG)
79
79
80 del Colors,InputColors
80 del Colors,InputColors
81
81
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83 def multiple_replace(dict, text):
83 def multiple_replace(dict, text):
84 """ Replace in 'text' all occurences of any key in the given
84 """ Replace in 'text' all occurences of any key in the given
85 dictionary by its corresponding value. Returns the new string."""
85 dictionary by its corresponding value. Returns the new string."""
86
86
87 # Function by Xavier Defrang, originally found at:
87 # Function by Xavier Defrang, originally found at:
88 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
88 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
89
89
90 # Create a regular expression from the dictionary keys
90 # Create a regular expression from the dictionary keys
91 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
91 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
92 # For each match, look-up corresponding value in dictionary
92 # For each match, look-up corresponding value in dictionary
93 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
93 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
94
94
95 #-----------------------------------------------------------------------------
95 #-----------------------------------------------------------------------------
96 # Special characters that can be used in prompt templates, mainly bash-like
96 # Special characters that can be used in prompt templates, mainly bash-like
97
97
98 # If $HOME isn't defined (Windows), make it an absurd string so that it can
98 # If $HOME isn't defined (Windows), make it an absurd string so that it can
99 # never be expanded out into '~'. Basically anything which can never be a
99 # never be expanded out into '~'. Basically anything which can never be a
100 # reasonable directory name will do, we just want the $HOME -> '~' operation
100 # reasonable directory name will do, we just want the $HOME -> '~' operation
101 # to become a no-op. We pre-compute $HOME here so it's not done on every
101 # to become a no-op. We pre-compute $HOME here so it's not done on every
102 # prompt call.
102 # prompt call.
103
103
104 # FIXME:
104 # FIXME:
105
105
106 # - This should be turned into a class which does proper namespace management,
106 # - This should be turned into a class which does proper namespace management,
107 # since the prompt specials need to be evaluated in a certain namespace.
107 # since the prompt specials need to be evaluated in a certain namespace.
108 # Currently it's just globals, which need to be managed manually by code
108 # Currently it's just globals, which need to be managed manually by code
109 # below.
109 # below.
110
110
111 # - I also need to split up the color schemes from the prompt specials
111 # - I also need to split up the color schemes from the prompt specials
112 # somehow. I don't have a clean design for that quite yet.
112 # somehow. I don't have a clean design for that quite yet.
113
113
114 HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")
114 HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")
115
115
116 # We precompute a few more strings here for the prompt_specials, which are
116 # We precompute a few more strings here for the prompt_specials, which are
117 # fixed once ipython starts. This reduces the runtime overhead of computing
117 # fixed once ipython starts. This reduces the runtime overhead of computing
118 # prompt strings.
118 # prompt strings.
119 USER = os.environ.get("USER")
119 USER = os.environ.get("USER")
120 HOSTNAME = socket.gethostname()
120 HOSTNAME = socket.gethostname()
121 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
121 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
122 ROOT_SYMBOL = "$#"[os.name=='nt' or os.getuid()==0]
122 ROOT_SYMBOL = "$#"[os.name=='nt' or os.getuid()==0]
123
123
124 prompt_specials_color = {
124 prompt_specials_color = {
125 # Prompt/history count
125 # Prompt/history count
126 '%n' : '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
126 '%n' : '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
127 r'\#': '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
127 r'\#': '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
128 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
128 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
129 # can get numbers displayed in whatever color they want.
129 # can get numbers displayed in whatever color they want.
130 r'\N': '${self.cache.prompt_count}',
130 r'\N': '${self.cache.prompt_count}',
131 # Prompt/history count, with the actual digits replaced by dots. Used
131 # Prompt/history count, with the actual digits replaced by dots. Used
132 # mainly in continuation prompts (prompt_in2)
132 # mainly in continuation prompts (prompt_in2)
133 r'\D': '${"."*len(str(self.cache.prompt_count))}',
133 r'\D': '${"."*len(str(self.cache.prompt_count))}',
134 # Current working directory
134 # Current working directory
135 r'\w': '${os.getcwd()}',
135 r'\w': '${os.getcwd()}',
136 # Current time
136 # Current time
137 r'\t' : '${time.strftime("%H:%M:%S")}',
137 r'\t' : '${time.strftime("%H:%M:%S")}',
138 # Basename of current working directory.
138 # Basename of current working directory.
139 # (use os.sep to make this portable across OSes)
139 # (use os.sep to make this portable across OSes)
140 r'\W' : '${os.getcwd().split("%s")[-1]}' % os.sep,
140 r'\W' : '${os.getcwd().split("%s")[-1]}' % os.sep,
141 # These X<N> are an extension to the normal bash prompts. They return
141 # These X<N> are an extension to the normal bash prompts. They return
142 # N terms of the path, after replacing $HOME with '~'
142 # N terms of the path, after replacing $HOME with '~'
143 r'\X0': '${os.getcwd().replace("%s","~")}' % HOME,
143 r'\X0': '${os.getcwd().replace("%s","~")}' % HOME,
144 r'\X1': '${self.cwd_filt(1)}',
144 r'\X1': '${self.cwd_filt(1)}',
145 r'\X2': '${self.cwd_filt(2)}',
145 r'\X2': '${self.cwd_filt(2)}',
146 r'\X3': '${self.cwd_filt(3)}',
146 r'\X3': '${self.cwd_filt(3)}',
147 r'\X4': '${self.cwd_filt(4)}',
147 r'\X4': '${self.cwd_filt(4)}',
148 r'\X5': '${self.cwd_filt(5)}',
148 r'\X5': '${self.cwd_filt(5)}',
149 # Y<N> are similar to X<N>, but they show '~' if it's the directory
149 # Y<N> are similar to X<N>, but they show '~' if it's the directory
150 # N+1 in the list. Somewhat like %cN in tcsh.
150 # N+1 in the list. Somewhat like %cN in tcsh.
151 r'\Y0': '${self.cwd_filt2(0)}',
151 r'\Y0': '${self.cwd_filt2(0)}',
152 r'\Y1': '${self.cwd_filt2(1)}',
152 r'\Y1': '${self.cwd_filt2(1)}',
153 r'\Y2': '${self.cwd_filt2(2)}',
153 r'\Y2': '${self.cwd_filt2(2)}',
154 r'\Y3': '${self.cwd_filt2(3)}',
154 r'\Y3': '${self.cwd_filt2(3)}',
155 r'\Y4': '${self.cwd_filt2(4)}',
155 r'\Y4': '${self.cwd_filt2(4)}',
156 r'\Y5': '${self.cwd_filt2(5)}',
156 r'\Y5': '${self.cwd_filt2(5)}',
157 # Hostname up to first .
157 # Hostname up to first .
158 r'\h': HOSTNAME_SHORT,
158 r'\h': HOSTNAME_SHORT,
159 # Full hostname
159 # Full hostname
160 r'\H': HOSTNAME,
160 r'\H': HOSTNAME,
161 # Username of current user
161 # Username of current user
162 r'\u': USER,
162 r'\u': USER,
163 # Escaped '\'
163 # Escaped '\'
164 '\\\\': '\\',
164 '\\\\': '\\',
165 # Newline
165 # Newline
166 r'\n': '\n',
166 r'\n': '\n',
167 # Carriage return
167 # Carriage return
168 r'\r': '\r',
168 r'\r': '\r',
169 # Release version
169 # Release version
170 r'\v': __version__,
170 r'\v': __version__,
171 # Root symbol ($ or #)
171 # Root symbol ($ or #)
172 r'\$': ROOT_SYMBOL,
172 r'\$': ROOT_SYMBOL,
173 }
173 }
174
174
175 # A copy of the prompt_specials dictionary but with all color escapes removed,
175 # A copy of the prompt_specials dictionary but with all color escapes removed,
176 # so we can correctly compute the prompt length for the auto_rewrite method.
176 # so we can correctly compute the prompt length for the auto_rewrite method.
177 prompt_specials_nocolor = prompt_specials_color.copy()
177 prompt_specials_nocolor = prompt_specials_color.copy()
178 prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}'
178 prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}'
179 prompt_specials_nocolor[r'\#'] = '${self.cache.prompt_count}'
179 prompt_specials_nocolor[r'\#'] = '${self.cache.prompt_count}'
180
180
181 # Add in all the InputTermColors color escapes as valid prompt characters.
181 # Add in all the InputTermColors color escapes as valid prompt characters.
182 # They all get added as \\C_COLORNAME, so that we don't have any conflicts
182 # They all get added as \\C_COLORNAME, so that we don't have any conflicts
183 # with a color name which may begin with a letter used by any other of the
183 # with a color name which may begin with a letter used by any other of the
184 # allowed specials. This of course means that \\C will never be allowed for
184 # allowed specials. This of course means that \\C will never be allowed for
185 # anything else.
185 # anything else.
186 input_colors = ColorANSI.InputTermColors
186 input_colors = ColorANSI.InputTermColors
187 for _color in dir(input_colors):
187 for _color in dir(input_colors):
188 if _color[0] != '_':
188 if _color[0] != '_':
189 c_name = r'\C_'+_color
189 c_name = r'\C_'+_color
190 prompt_specials_color[c_name] = getattr(input_colors,_color)
190 prompt_specials_color[c_name] = getattr(input_colors,_color)
191 prompt_specials_nocolor[c_name] = ''
191 prompt_specials_nocolor[c_name] = ''
192
192
193 # we default to no color for safety. Note that prompt_specials is a global
193 # we default to no color for safety. Note that prompt_specials is a global
194 # variable used by all prompt objects.
194 # variable used by all prompt objects.
195 prompt_specials = prompt_specials_nocolor
195 prompt_specials = prompt_specials_nocolor
196
196
197 #-----------------------------------------------------------------------------
197 #-----------------------------------------------------------------------------
198 def str_safe(arg):
198 def str_safe(arg):
199 """Convert to a string, without ever raising an exception.
199 """Convert to a string, without ever raising an exception.
200
200
201 If str(arg) fails, <ERROR: ... > is returned, where ... is the exception
201 If str(arg) fails, <ERROR: ... > is returned, where ... is the exception
202 error message."""
202 error message."""
203
203
204 try:
204 try:
205 out = str(arg)
205 out = str(arg)
206 except UnicodeError:
206 except UnicodeError:
207 try:
207 try:
208 out = arg.encode('utf_8','replace')
208 out = arg.encode('utf_8','replace')
209 except Exception,msg:
209 except Exception,msg:
210 # let's keep this little duplication here, so that the most common
210 # let's keep this little duplication here, so that the most common
211 # case doesn't suffer from a double try wrapping.
211 # case doesn't suffer from a double try wrapping.
212 out = '<ERROR: %s>' % msg
212 out = '<ERROR: %s>' % msg
213 except Exception,msg:
213 except Exception,msg:
214 out = '<ERROR: %s>' % msg
214 out = '<ERROR: %s>' % msg
215 return out
215 return out
216
216
217 class BasePrompt:
217 class BasePrompt:
218 """Interactive prompt similar to Mathematica's."""
218 """Interactive prompt similar to Mathematica's."""
219 def __init__(self,cache,sep,prompt,pad_left=False):
219 def __init__(self,cache,sep,prompt,pad_left=False):
220
220
221 # Hack: we access information about the primary prompt through the
221 # Hack: we access information about the primary prompt through the
222 # cache argument. We need this, because we want the secondary prompt
222 # cache argument. We need this, because we want the secondary prompt
223 # to be aligned with the primary one. Color table info is also shared
223 # to be aligned with the primary one. Color table info is also shared
224 # by all prompt classes through the cache. Nice OO spaghetti code!
224 # by all prompt classes through the cache. Nice OO spaghetti code!
225 self.cache = cache
225 self.cache = cache
226 self.sep = sep
226 self.sep = sep
227
227
228 # regexp to count the number of spaces at the end of a prompt
228 # regexp to count the number of spaces at the end of a prompt
229 # expression, useful for prompt auto-rewriting
229 # expression, useful for prompt auto-rewriting
230 self.rspace = re.compile(r'(\s*)$')
230 self.rspace = re.compile(r'(\s*)$')
231 # Flag to left-pad prompt strings to match the length of the primary
231 # Flag to left-pad prompt strings to match the length of the primary
232 # prompt
232 # prompt
233 self.pad_left = pad_left
233 self.pad_left = pad_left
234 # Set template to create each actual prompt (where numbers change)
234 # Set template to create each actual prompt (where numbers change)
235 self.p_template = prompt
235 self.p_template = prompt
236 self.set_p_str()
236 self.set_p_str()
237
237
238 def set_p_str(self):
238 def set_p_str(self):
239 """ Set the interpolating prompt strings.
239 """ Set the interpolating prompt strings.
240
240
241 This must be called every time the color settings change, because the
241 This must be called every time the color settings change, because the
242 prompt_specials global may have changed."""
242 prompt_specials global may have changed."""
243
243
244 import os,time # needed in locals for prompt string handling
244 import os,time # needed in locals for prompt string handling
245 loc = locals()
245 loc = locals()
246 self.p_str = ItplNS('%s%s%s' %
246 self.p_str = ItplNS('%s%s%s' %
247 ('${self.sep}${self.col_p}',
247 ('${self.sep}${self.col_p}',
248 multiple_replace(prompt_specials, self.p_template),
248 multiple_replace(prompt_specials, self.p_template),
249 '${self.col_norm}'),self.cache.user_ns,loc)
249 '${self.col_norm}'),self.cache.user_ns,loc)
250
250
251 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
251 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
252 self.p_template),
252 self.p_template),
253 self.cache.user_ns,loc)
253 self.cache.user_ns,loc)
254
254
255 def write(self,msg): # dbg
255 def write(self,msg): # dbg
256 sys.stdout.write(msg)
256 sys.stdout.write(msg)
257 return ''
257 return ''
258
258
259 def __str__(self):
259 def __str__(self):
260 """Return a string form of the prompt.
260 """Return a string form of the prompt.
261
261
262 This for is useful for continuation and output prompts, since it is
262 This for is useful for continuation and output prompts, since it is
263 left-padded to match lengths with the primary one (if the
263 left-padded to match lengths with the primary one (if the
264 self.pad_left attribute is set)."""
264 self.pad_left attribute is set)."""
265
265
266 out_str = str_safe(self.p_str)
266 out_str = str_safe(self.p_str)
267 if self.pad_left:
267 if self.pad_left:
268 # We must find the amount of padding required to match lengths,
268 # We must find the amount of padding required to match lengths,
269 # taking the color escapes (which are invisible on-screen) into
269 # taking the color escapes (which are invisible on-screen) into
270 # account.
270 # account.
271 esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor))
271 esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor))
272 format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad)
272 format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad)
273 return format % out_str
273 return format % out_str
274 else:
274 else:
275 return out_str
275 return out_str
276
276
277 # these path filters are put in as methods so that we can control the
277 # these path filters are put in as methods so that we can control the
278 # namespace where the prompt strings get evaluated
278 # namespace where the prompt strings get evaluated
279 def cwd_filt(self,depth):
279 def cwd_filt(self,depth):
280 """Return the last depth elements of the current working directory.
280 """Return the last depth elements of the current working directory.
281
281
282 $HOME is always replaced with '~'.
282 $HOME is always replaced with '~'.
283 If depth==0, the full path is returned."""
283 If depth==0, the full path is returned."""
284
284
285 cwd = os.getcwd().replace(HOME,"~")
285 cwd = os.getcwd().replace(HOME,"~")
286 out = os.sep.join(cwd.split(os.sep)[-depth:])
286 out = os.sep.join(cwd.split(os.sep)[-depth:])
287 if out:
287 if out:
288 return out
288 return out
289 else:
289 else:
290 return os.sep
290 return os.sep
291
291
292 def cwd_filt2(self,depth):
292 def cwd_filt2(self,depth):
293 """Return the last depth elements of the current working directory.
293 """Return the last depth elements of the current working directory.
294
294
295 $HOME is always replaced with '~'.
295 $HOME is always replaced with '~'.
296 If depth==0, the full path is returned."""
296 If depth==0, the full path is returned."""
297
297
298 cwd = os.getcwd().replace(HOME,"~").split(os.sep)
298 cwd = os.getcwd().replace(HOME,"~").split(os.sep)
299 if '~' in cwd and len(cwd) == depth+1:
299 if '~' in cwd and len(cwd) == depth+1:
300 depth += 1
300 depth += 1
301 out = os.sep.join(cwd[-depth:])
301 out = os.sep.join(cwd[-depth:])
302 if out:
302 if out:
303 return out
303 return out
304 else:
304 else:
305 return os.sep
305 return os.sep
306
306
307 class Prompt1(BasePrompt):
307 class Prompt1(BasePrompt):
308 """Input interactive prompt similar to Mathematica's."""
308 """Input interactive prompt similar to Mathematica's."""
309
309
310 def __init__(self,cache,sep='\n',prompt='In [\\#]: ',pad_left=True):
310 def __init__(self,cache,sep='\n',prompt='In [\\#]: ',pad_left=True):
311 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
311 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
312
312
313 def set_colors(self):
313 def set_colors(self):
314 self.set_p_str()
314 self.set_p_str()
315 Colors = self.cache.color_table.active_colors # shorthand
315 Colors = self.cache.color_table.active_colors # shorthand
316 self.col_p = Colors.in_prompt
316 self.col_p = Colors.in_prompt
317 self.col_num = Colors.in_number
317 self.col_num = Colors.in_number
318 self.col_norm = Colors.in_normal
318 self.col_norm = Colors.in_normal
319 # We need a non-input version of these escapes for the '--->'
319 # We need a non-input version of these escapes for the '--->'
320 # auto-call prompts used in the auto_rewrite() method.
320 # auto-call prompts used in the auto_rewrite() method.
321 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
321 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
322 self.col_norm_ni = Colors.normal
322 self.col_norm_ni = Colors.normal
323
323
324 def __str__(self):
324 def __str__(self):
325 self.cache.prompt_count += 1
325 self.cache.prompt_count += 1
326 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
326 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
327 return str_safe(self.p_str)
327 return str_safe(self.p_str)
328
328
329 def auto_rewrite(self):
329 def auto_rewrite(self):
330 """Print a string of the form '--->' which lines up with the previous
330 """Print a string of the form '--->' which lines up with the previous
331 input string. Useful for systems which re-write the user input when
331 input string. Useful for systems which re-write the user input when
332 handling automatically special syntaxes."""
332 handling automatically special syntaxes."""
333
333
334 curr = str(self.cache.last_prompt)
334 curr = str(self.cache.last_prompt)
335 nrspaces = len(self.rspace.search(curr).group())
335 nrspaces = len(self.rspace.search(curr).group())
336 return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
336 return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
337 ' '*nrspaces,self.col_norm_ni)
337 ' '*nrspaces,self.col_norm_ni)
338
338
339 class PromptOut(BasePrompt):
339 class PromptOut(BasePrompt):
340 """Output interactive prompt similar to Mathematica's."""
340 """Output interactive prompt similar to Mathematica's."""
341
341
342 def __init__(self,cache,sep='',prompt='Out[\\#]: ',pad_left=True):
342 def __init__(self,cache,sep='',prompt='Out[\\#]: ',pad_left=True):
343 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
343 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
344 if not self.p_template:
344 if not self.p_template:
345 self.__str__ = lambda: ''
345 self.__str__ = lambda: ''
346
346
347 def set_colors(self):
347 def set_colors(self):
348 self.set_p_str()
348 self.set_p_str()
349 Colors = self.cache.color_table.active_colors # shorthand
349 Colors = self.cache.color_table.active_colors # shorthand
350 self.col_p = Colors.out_prompt
350 self.col_p = Colors.out_prompt
351 self.col_num = Colors.out_number
351 self.col_num = Colors.out_number
352 self.col_norm = Colors.normal
352 self.col_norm = Colors.normal
353
353
354 class Prompt2(BasePrompt):
354 class Prompt2(BasePrompt):
355 """Interactive continuation prompt."""
355 """Interactive continuation prompt."""
356
356
357 def __init__(self,cache,prompt=' .\\D.: ',pad_left=True):
357 def __init__(self,cache,prompt=' .\\D.: ',pad_left=True):
358 self.cache = cache
358 self.cache = cache
359 self.p_template = prompt
359 self.p_template = prompt
360 self.pad_left = pad_left
360 self.pad_left = pad_left
361 self.set_p_str()
361 self.set_p_str()
362
362
363 def set_p_str(self):
363 def set_p_str(self):
364 import os,time # needed in locals for prompt string handling
364 import os,time # needed in locals for prompt string handling
365 loc = locals()
365 loc = locals()
366 self.p_str = ItplNS('%s%s%s' %
366 self.p_str = ItplNS('%s%s%s' %
367 ('${self.col_p2}',
367 ('${self.col_p2}',
368 multiple_replace(prompt_specials, self.p_template),
368 multiple_replace(prompt_specials, self.p_template),
369 '$self.col_norm'),
369 '$self.col_norm'),
370 self.cache.user_ns,loc)
370 self.cache.user_ns,loc)
371 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
371 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
372 self.p_template),
372 self.p_template),
373 self.cache.user_ns,loc)
373 self.cache.user_ns,loc)
374
374
375 def set_colors(self):
375 def set_colors(self):
376 self.set_p_str()
376 self.set_p_str()
377 Colors = self.cache.color_table.active_colors
377 Colors = self.cache.color_table.active_colors
378 self.col_p2 = Colors.in_prompt2
378 self.col_p2 = Colors.in_prompt2
379 self.col_norm = Colors.in_normal
379 self.col_norm = Colors.in_normal
380 # FIXME (2004-06-16) HACK: prevent crashes for users who haven't
380 # FIXME (2004-06-16) HACK: prevent crashes for users who haven't
381 # updated their prompt_in2 definitions. Remove eventually.
381 # updated their prompt_in2 definitions. Remove eventually.
382 self.col_p = Colors.out_prompt
382 self.col_p = Colors.out_prompt
383 self.col_num = Colors.out_number
383 self.col_num = Colors.out_number
384
384
385
385
386 #-----------------------------------------------------------------------------
386 #-----------------------------------------------------------------------------
387 class CachedOutput:
387 class CachedOutput:
388 """Class for printing output from calculations while keeping a cache of
388 """Class for printing output from calculations while keeping a cache of
389 reults. It dynamically creates global variables prefixed with _ which
389 reults. It dynamically creates global variables prefixed with _ which
390 contain these results.
390 contain these results.
391
391
392 Meant to be used as a sys.displayhook replacement, providing numbered
392 Meant to be used as a sys.displayhook replacement, providing numbered
393 prompts and cache services.
393 prompts and cache services.
394
394
395 Initialize with initial and final values for cache counter (this defines
395 Initialize with initial and final values for cache counter (this defines
396 the maximum size of the cache."""
396 the maximum size of the cache."""
397
397
398 def __init__(self,shell,cache_size,Pprint,
398 def __init__(self,shell,cache_size,Pprint,
399 colors='NoColor',input_sep='\n',
399 colors='NoColor',input_sep='\n',
400 output_sep='\n',output_sep2='',
400 output_sep='\n',output_sep2='',
401 ps1 = None, ps2 = None,ps_out = None,pad_left=True):
401 ps1 = None, ps2 = None,ps_out = None,pad_left=True):
402
402
403 cache_size_min = 3
403 cache_size_min = 3
404 if cache_size <= 0:
404 if cache_size <= 0:
405 self.do_full_cache = 0
405 self.do_full_cache = 0
406 cache_size = 0
406 cache_size = 0
407 elif cache_size < cache_size_min:
407 elif cache_size < cache_size_min:
408 self.do_full_cache = 0
408 self.do_full_cache = 0
409 cache_size = 0
409 cache_size = 0
410 warn('caching was disabled (min value for cache size is %s).' %
410 warn('caching was disabled (min value for cache size is %s).' %
411 cache_size_min,level=3)
411 cache_size_min,level=3)
412 else:
412 else:
413 self.do_full_cache = 1
413 self.do_full_cache = 1
414
414
415 self.cache_size = cache_size
415 self.cache_size = cache_size
416 self.input_sep = input_sep
416 self.input_sep = input_sep
417
417
418 # we need a reference to the user-level namespace
418 # we need a reference to the user-level namespace
419 self.shell = shell
419 self.shell = shell
420 self.user_ns = shell.user_ns
420 self.user_ns = shell.user_ns
421 # and to the user's input
421 # and to the user's input
422 self.input_hist = shell.input_hist
422 self.input_hist = shell.input_hist
423 # and to the user's logger, for logging output
423 # and to the user's logger, for logging output
424 self.logger = shell.logger
424 self.logger = shell.logger
425
425
426 # Set input prompt strings and colors
426 # Set input prompt strings and colors
427 if cache_size == 0:
427 if cache_size == 0:
428 if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
428 if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
429 or ps1.find(r'\N') > -1:
429 or ps1.find(r'\N') > -1:
430 ps1 = '>>> '
430 ps1 = '>>> '
431 if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
431 if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
432 or ps2.find(r'\N') > -1:
432 or ps2.find(r'\N') > -1:
433 ps2 = '... '
433 ps2 = '... '
434 self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
434 self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
435 self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
435 self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
436 self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
436 self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
437
437
438 self.color_table = PromptColors
438 self.color_table = PromptColors
439 self.prompt1 = Prompt1(self,sep=input_sep,prompt=self.ps1_str,
439 self.prompt1 = Prompt1(self,sep=input_sep,prompt=self.ps1_str,
440 pad_left=pad_left)
440 pad_left=pad_left)
441 self.prompt2 = Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
441 self.prompt2 = Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
442 self.prompt_out = PromptOut(self,sep='',prompt=self.ps_out_str,
442 self.prompt_out = PromptOut(self,sep='',prompt=self.ps_out_str,
443 pad_left=pad_left)
443 pad_left=pad_left)
444 self.set_colors(colors)
444 self.set_colors(colors)
445
445
446 # other more normal stuff
446 # other more normal stuff
447 # b/c each call to the In[] prompt raises it by 1, even the first.
447 # b/c each call to the In[] prompt raises it by 1, even the first.
448 self.prompt_count = 0
448 self.prompt_count = 0
449 # Store the last prompt string each time, we need it for aligning
449 # Store the last prompt string each time, we need it for aligning
450 # continuation and auto-rewrite prompts
450 # continuation and auto-rewrite prompts
451 self.last_prompt = ''
451 self.last_prompt = ''
452 self.Pprint = Pprint
452 self.Pprint = Pprint
453 self.output_sep = output_sep
453 self.output_sep = output_sep
454 self.output_sep2 = output_sep2
454 self.output_sep2 = output_sep2
455 self._,self.__,self.___ = '','',''
455 self._,self.__,self.___ = '','',''
456 self.pprint_types = map(type,[(),[],{}])
456 self.pprint_types = map(type,[(),[],{}])
457
457
458 # these are deliberately global:
458 # these are deliberately global:
459 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
459 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
460 self.user_ns.update(to_user_ns)
460 self.user_ns.update(to_user_ns)
461
461
462 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
462 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
463 if p_str is None:
463 if p_str is None:
464 if self.do_full_cache:
464 if self.do_full_cache:
465 return cache_def
465 return cache_def
466 else:
466 else:
467 return no_cache_def
467 return no_cache_def
468 else:
468 else:
469 return p_str
469 return p_str
470
470
471 def set_colors(self,colors):
471 def set_colors(self,colors):
472 """Set the active color scheme and configure colors for the three
472 """Set the active color scheme and configure colors for the three
473 prompt subsystems."""
473 prompt subsystems."""
474
474
475 # FIXME: the prompt_specials global should be gobbled inside this
475 # FIXME: the prompt_specials global should be gobbled inside this
476 # class instead. Do it when cleaning up the whole 3-prompt system.
476 # class instead. Do it when cleaning up the whole 3-prompt system.
477 global prompt_specials
477 global prompt_specials
478 if colors.lower()=='nocolor':
478 if colors.lower()=='nocolor':
479 prompt_specials = prompt_specials_nocolor
479 prompt_specials = prompt_specials_nocolor
480 else:
480 else:
481 prompt_specials = prompt_specials_color
481 prompt_specials = prompt_specials_color
482
482
483 self.color_table.set_active_scheme(colors)
483 self.color_table.set_active_scheme(colors)
484 self.prompt1.set_colors()
484 self.prompt1.set_colors()
485 self.prompt2.set_colors()
485 self.prompt2.set_colors()
486 self.prompt_out.set_colors()
486 self.prompt_out.set_colors()
487
487
488 def __call__(self,arg=None):
488 def __call__(self,arg=None):
489 """Printing with history cache management.
489 """Printing with history cache management.
490
490
491 This is invoked everytime the interpreter needs to print, and is
491 This is invoked everytime the interpreter needs to print, and is
492 activated by setting the variable sys.displayhook to it."""
492 activated by setting the variable sys.displayhook to it."""
493
493
494 # If something injected a '_' variable in __builtin__, delete
494 # If something injected a '_' variable in __builtin__, delete
495 # ipython's automatic one so we don't clobber that. gettext() in
495 # ipython's automatic one so we don't clobber that. gettext() in
496 # particular uses _, so we need to stay away from it.
496 # particular uses _, so we need to stay away from it.
497 if '_' in __builtin__.__dict__:
497 if '_' in __builtin__.__dict__:
498 try:
498 try:
499 del self.user_ns['_']
499 del self.user_ns['_']
500 except KeyError:
500 except KeyError:
501 pass
501 pass
502 if arg is not None:
502 if arg is not None:
503 cout_write = Term.cout.write # fast lookup
503 cout_write = Term.cout.write # fast lookup
504 # first handle the cache and counters
504 # first handle the cache and counters
505
505
506 # do not print output if input ends in ';'
506 # do not print output if input ends in ';'
507 if self.input_hist[self.prompt_count].endswith(';\n'):
507 if self.input_hist[self.prompt_count].endswith(';\n'):
508 return
508 return
509 # don't use print, puts an extra space
509 # don't use print, puts an extra space
510 cout_write(self.output_sep)
510 cout_write(self.output_sep)
511 outprompt = self.shell.hooks.generate_output_prompt()
511 outprompt = self.shell.hooks.generate_output_prompt()
512 if self.do_full_cache:
512 if self.do_full_cache:
513 cout_write(outprompt)
513 cout_write(outprompt)
514
514
515 if isinstance(arg,Macro):
516 print 'Executing Macro...'
517 # in case the macro takes a long time to execute
518 Term.cout.flush()
519 self.shell.runlines(arg.value)
520 return None
521
522 # and now call a possibly user-defined print mechanism
515 # and now call a possibly user-defined print mechanism
523 manipulated_val = self.display(arg)
516 manipulated_val = self.display(arg)
524
517
525 # user display hooks can change the variable to be stored in
518 # user display hooks can change the variable to be stored in
526 # output history
519 # output history
527
520
528 if manipulated_val is not None:
521 if manipulated_val is not None:
529 arg = manipulated_val
522 arg = manipulated_val
530
523
531 # avoid recursive reference when displaying _oh/Out
524 # avoid recursive reference when displaying _oh/Out
532 if arg is not self.user_ns['_oh']:
525 if arg is not self.user_ns['_oh']:
533 self.update(arg)
526 self.update(arg)
534
527
535 if self.logger.log_output:
528 if self.logger.log_output:
536 self.logger.log_write(repr(arg),'output')
529 self.logger.log_write(repr(arg),'output')
537 cout_write(self.output_sep2)
530 cout_write(self.output_sep2)
538 Term.cout.flush()
531 Term.cout.flush()
539
532
540 def _display(self,arg):
533 def _display(self,arg):
541 """Default printer method, uses pprint.
534 """Default printer method, uses pprint.
542
535
543 Do ip.set_hook("result_display", my_displayhook) for custom result
536 Do ip.set_hook("result_display", my_displayhook) for custom result
544 display, e.g. when your own objects need special formatting.
537 display, e.g. when your own objects need special formatting.
545 """
538 """
546
539
547 return self.shell.hooks.result_display(arg)
540 return self.shell.hooks.result_display(arg)
548
541
549 # Assign the default display method:
542 # Assign the default display method:
550 display = _display
543 display = _display
551
544
552 def update(self,arg):
545 def update(self,arg):
553 #print '***cache_count', self.cache_count # dbg
546 #print '***cache_count', self.cache_count # dbg
554 if len(self.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
547 if len(self.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
555 warn('Output cache limit (currently '+
548 warn('Output cache limit (currently '+
556 `self.cache_size`+' entries) hit.\n'
549 `self.cache_size`+' entries) hit.\n'
557 'Flushing cache and resetting history counter...\n'
550 'Flushing cache and resetting history counter...\n'
558 'The only history variables available will be _,__,___ and _1\n'
551 'The only history variables available will be _,__,___ and _1\n'
559 'with the current result.')
552 'with the current result.')
560
553
561 self.flush()
554 self.flush()
562 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
555 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
563 # we cause buggy behavior for things like gettext).
556 # we cause buggy behavior for things like gettext).
564 if '_' not in __builtin__.__dict__:
557 if '_' not in __builtin__.__dict__:
565 self.___ = self.__
558 self.___ = self.__
566 self.__ = self._
559 self.__ = self._
567 self._ = arg
560 self._ = arg
568 self.user_ns.update({'_':self._,'__':self.__,'___':self.___})
561 self.user_ns.update({'_':self._,'__':self.__,'___':self.___})
569
562
570 # hackish access to top-level namespace to create _1,_2... dynamically
563 # hackish access to top-level namespace to create _1,_2... dynamically
571 to_main = {}
564 to_main = {}
572 if self.do_full_cache:
565 if self.do_full_cache:
573 new_result = '_'+`self.prompt_count`
566 new_result = '_'+`self.prompt_count`
574 to_main[new_result] = arg
567 to_main[new_result] = arg
575 self.user_ns.update(to_main)
568 self.user_ns.update(to_main)
576 self.user_ns['_oh'][self.prompt_count] = arg
569 self.user_ns['_oh'][self.prompt_count] = arg
577
570
578 def flush(self):
571 def flush(self):
579 if not self.do_full_cache:
572 if not self.do_full_cache:
580 raise ValueError,"You shouldn't have reached the cache flush "\
573 raise ValueError,"You shouldn't have reached the cache flush "\
581 "if full caching is not enabled!"
574 "if full caching is not enabled!"
582 # delete auto-generated vars from global namespace
575 # delete auto-generated vars from global namespace
583
576
584 for n in range(1,self.prompt_count + 1):
577 for n in range(1,self.prompt_count + 1):
585 key = '_'+`n`
578 key = '_'+`n`
586 try:
579 try:
587 del self.user_ns[key]
580 del self.user_ns[key]
588 except: pass
581 except: pass
589 self.user_ns['_oh'].clear()
582 self.user_ns['_oh'].clear()
590
583
591 if '_' not in __builtin__.__dict__:
584 if '_' not in __builtin__.__dict__:
592 self.user_ns.update({'_':None,'__':None, '___':None})
585 self.user_ns.update({'_':None,'__':None, '___':None})
593 import gc
586 import gc
594 gc.collect() # xxx needed?
587 gc.collect() # xxx needed?
595
588
@@ -1,26 +1,38 b''
1 """Support for interactive macros in IPython"""
1 """Support for interactive macros in IPython"""
2
2
3 #*****************************************************************************
3 #*****************************************************************************
4 # Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
4 # Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #*****************************************************************************
8 #*****************************************************************************
9
9
10 import IPython.ipapi
11
12
13 from IPython.genutils import Term
14
15
10 class Macro:
16 class Macro:
11 """Simple class to store the value of macros as strings.
17 """Simple class to store the value of macros as strings.
12
18
13 This allows us to later exec them by checking when something is an
19 Macro is just a callable that executes a string of IPython
14 instance of this class."""
20 input when called.
21 """
15
22
16 def __init__(self,data):
23 def __init__(self,data):
17
24
18 # store the macro value, as a single string which can be evaluated by
25 # store the macro value, as a single string which can be evaluated by
19 # runlines()
26 # runlines()
20 self.value = ''.join(data).rstrip()+'\n'
27 self.value = ''.join(data).rstrip()+'\n'
21
28
22 def __str__(self):
29 def __str__(self):
23 return self.value
30 return self.value
24
31
25 def __repr__(self):
32 def __repr__(self):
26 return 'IPython.macro.Macro(%s)' % repr(self.value)
33 return 'IPython.macro.Macro(%s)' % repr(self.value)
34
35 def __call__(self):
36 Term.cout.flush()
37 ip = IPython.ipapi.get()
38 ip.runlines(self.value) No newline at end of file
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now