##// END OF EJS Templates
Fix small inconsistency in display hook (needed for a SAGE fix)
fperez -
Show More

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

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