##// END OF EJS Templates
Expand tabs to 4 spaces in %history.
Fernando Perez -
Show More
@@ -1,279 +1,282 b''
1 1 # -*- coding: utf-8 -*-
2 2 """ History related magics and functionality """
3 3
4 4 # Stdlib imports
5 5 import fnmatch
6 6 import os
7 7
8 8 import IPython.utils.io
9 9 from IPython.utils.io import ask_yes_no
10 10 from IPython.utils.warn import warn
11 11 from IPython.core import ipapi
12 12
13 13 def magic_history(self, parameter_s = ''):
14 14 """Print input history (_i<n> variables), with most recent last.
15 15
16 16 %history -> print at most 40 inputs (some may be multi-line)\\
17 17 %history n -> print at most n inputs\\
18 18 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
19 19
20 20 By default, input history is printed without line numbers so it can be
21 21 directly pasted into an editor.
22 22
23 23 With -n, each input's number <n> is shown, and is accessible as the
24 24 automatically generated variable _i<n> as well as In[<n>]. Multi-line
25 25 statements are printed starting at a new line for easy copy/paste.
26 26
27 27 Options:
28 28
29 29 -n: print line numbers for each input.
30 30 This feature is only available if numbered prompts are in use.
31 31
32 32 -o: also print outputs for each input.
33 33
34 34 -p: print classic '>>>' python prompts before each input. This is useful
35 35 for making documentation, and in conjunction with -o, for producing
36 36 doctest-ready output.
37 37
38 38 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
39 39
40 40 -t: print the 'translated' history, as IPython understands it. IPython
41 41 filters your input and converts it all into valid Python source before
42 42 executing it (things like magics or aliases are turned into function
43 43 calls, for example). With this option, you'll see the native history
44 44 instead of the user-entered version: '%cd /' will be seen as
45 45 'get_ipython().magic("%cd /")' instead of '%cd /'.
46 46
47 47 -g: treat the arg as a pattern to grep for in (full) history.
48 48 This includes the "shadow history" (almost all commands ever written).
49 49 Use '%hist -g' to show full shadow history (may be very long).
50 50 In shadow history, every index nuwber starts with 0.
51 51
52 52 -f FILENAME: instead of printing the output to the screen, redirect it to
53 53 the given file. The file is always overwritten, though IPython asks for
54 54 confirmation first if it already exists.
55 55 """
56 56
57 57 if not self.displayhook.do_full_cache:
58 58 print 'This feature is only available if numbered prompts are in use.'
59 59 return
60 60 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
61 61
62 62 # Check if output to specific file was requested.
63 63 try:
64 64 outfname = opts['f']
65 65 except KeyError:
66 66 outfile = IPython.utils.io.Term.cout # default
67 67 # We don't want to close stdout at the end!
68 68 close_at_end = False
69 69 else:
70 70 if os.path.exists(outfname):
71 71 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
72 72 print 'Aborting.'
73 73 return
74 74
75 75 outfile = open(outfname,'w')
76 76 close_at_end = True
77 77
78 78 if 't' in opts:
79 79 input_hist = self.input_hist
80 80 elif 'r' in opts:
81 81 input_hist = self.input_hist_raw
82 82 else:
83 83 # Raw history is the default
84 84 input_hist = self.input_hist_raw
85 85
86 86 default_length = 40
87 87 pattern = None
88 88 if 'g' in opts:
89 89 init = 1
90 90 final = len(input_hist)
91 91 parts = parameter_s.split(None, 1)
92 92 if len(parts) == 1:
93 93 parts += '*'
94 94 head, pattern = parts
95 95 pattern = "*" + pattern + "*"
96 96 elif len(args) == 0:
97 97 final = len(input_hist)-1
98 98 init = max(1,final-default_length)
99 99 elif len(args) == 1:
100 100 final = len(input_hist)
101 101 init = max(1, final-int(args[0]))
102 102 elif len(args) == 2:
103 103 init, final = map(int, args)
104 104 else:
105 105 warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
106 106 print >> IPython.utils.io.Term.cout, self.magic_hist.__doc__
107 107 return
108 108
109 109 width = len(str(final))
110 110 line_sep = ['','\n']
111 111 print_nums = 'n' in opts
112 112 print_outputs = 'o' in opts
113 113 pyprompts = 'p' in opts
114 114
115 115 found = False
116 116 if pattern is not None:
117 117 sh = self.shadowhist.all()
118 118 for idx, s in sh:
119 119 if fnmatch.fnmatch(s, pattern):
120 print >> outfile, "0%d: %s" %(idx, s)
120 print >> outfile, "0%d: %s" %(idx, s.expandtabs(4))
121 121 found = True
122 122
123 123 if found:
124 124 print >> outfile, "==="
125 125 print >> outfile, \
126 126 "shadow history ends, fetch by %rep <number> (must start with 0)"
127 127 print >> outfile, "=== start of normal history ==="
128 128
129 for in_num in range(init,final):
130 inline = input_hist[in_num]
129 for in_num in range(init,final):
130 # Print user history with tabs expanded to 4 spaces. The GUI clients
131 # use hard tabs for easier usability in auto-indented code, but we want
132 # to produce PEP-8 compliant history for safe pasting into an editor.
133 inline = input_hist[in_num].expandtabs(4)
131 134 if pattern is not None and not fnmatch.fnmatch(inline, pattern):
132 135 continue
133 136
134 137 multiline = int(inline.count('\n') > 1)
135 138 if print_nums:
136 139 print >> outfile, \
137 140 '%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
138 141 if pyprompts:
139 142 print >> outfile, '>>>',
140 143 if multiline:
141 144 lines = inline.splitlines()
142 145 print >> outfile, '\n... '.join(lines)
143 146 print >> outfile, '... '
144 147 else:
145 148 print >> outfile, inline,
146 149 else:
147 150 print >> outfile, inline,
148 151 if print_outputs:
149 152 output = self.shell.user_ns['Out'].get(in_num)
150 153 if output is not None:
151 154 print >> outfile, repr(output)
152 155
153 156 if close_at_end:
154 157 outfile.close()
155 158
156 159
157 160 def magic_hist(self, parameter_s=''):
158 161 """Alternate name for %history."""
159 162 return self.magic_history(parameter_s)
160 163
161 164
162 165 def rep_f(self, arg):
163 166 r""" Repeat a command, or get command to input line for editing
164 167
165 168 - %rep (no arguments):
166 169
167 170 Place a string version of last computation result (stored in the special '_'
168 171 variable) to the next input prompt. Allows you to create elaborate command
169 172 lines without using copy-paste::
170 173
171 174 $ l = ["hei", "vaan"]
172 175 $ "".join(l)
173 176 ==> heivaan
174 177 $ %rep
175 178 $ heivaan_ <== cursor blinking
176 179
177 180 %rep 45
178 181
179 182 Place history line 45 to next input prompt. Use %hist to find out the
180 183 number.
181 184
182 185 %rep 1-4 6-7 3
183 186
184 187 Repeat the specified lines immediately. Input slice syntax is the same as
185 188 in %macro and %save.
186 189
187 190 %rep foo
188 191
189 192 Place the most recent line that has the substring "foo" to next input.
190 193 (e.g. 'svn ci -m foobar').
191 194 """
192 195
193 196 opts,args = self.parse_options(arg,'',mode='list')
194 197 if not args:
195 198 self.set_next_input(str(self.user_ns["_"]))
196 199 return
197 200
198 201 if len(args) == 1 and not '-' in args[0]:
199 202 arg = args[0]
200 203 if len(arg) > 1 and arg.startswith('0'):
201 204 # get from shadow hist
202 205 num = int(arg[1:])
203 206 line = self.shadowhist.get(num)
204 207 self.set_next_input(str(line))
205 208 return
206 209 try:
207 210 num = int(args[0])
208 211 self.set_next_input(str(self.input_hist_raw[num]).rstrip())
209 212 return
210 213 except ValueError:
211 214 pass
212 215
213 216 for h in reversed(self.input_hist_raw):
214 217 if 'rep' in h:
215 218 continue
216 219 if fnmatch.fnmatch(h,'*' + arg + '*'):
217 220 self.set_next_input(str(h).rstrip())
218 221 return
219 222
220 223 try:
221 224 lines = self.extract_input_slices(args, True)
222 225 print "lines",lines
223 226 self.runlines(lines)
224 227 except ValueError:
225 228 print "Not found in recent history:", args
226 229
227 230
228 231 _sentinel = object()
229 232
230 233 class ShadowHist(object):
231 234 def __init__(self,db):
232 235 # cmd => idx mapping
233 236 self.curidx = 0
234 237 self.db = db
235 238 self.disabled = False
236 239
237 240 def inc_idx(self):
238 241 idx = self.db.get('shadowhist_idx', 1)
239 242 self.db['shadowhist_idx'] = idx + 1
240 243 return idx
241 244
242 245 def add(self, ent):
243 246 if self.disabled:
244 247 return
245 248 try:
246 249 old = self.db.hget('shadowhist', ent, _sentinel)
247 250 if old is not _sentinel:
248 251 return
249 252 newidx = self.inc_idx()
250 253 #print "new",newidx # dbg
251 254 self.db.hset('shadowhist',ent, newidx)
252 255 except:
253 256 ipapi.get().showtraceback()
254 257 print "WARNING: disabling shadow history"
255 258 self.disabled = True
256 259
257 260 def all(self):
258 261 d = self.db.hdict('shadowhist')
259 262 items = [(i,s) for (s,i) in d.items()]
260 263 items.sort()
261 264 return items
262 265
263 266 def get(self, idx):
264 267 all = self.all()
265 268
266 269 for k, v in all:
267 270 #print k,v
268 271 if k == idx:
269 272 return v
270 273
271 274
272 275 def init_ipython(ip):
273 276 ip.define_magic("rep",rep_f)
274 277 ip.define_magic("hist",magic_hist)
275 278 ip.define_magic("history",magic_history)
276 279
277 280 # XXX - ipy_completers are in quarantine, need to be updated to new apis
278 281 #import ipy_completers
279 282 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
General Comments 0
You need to be logged in to leave comments. Login now