##// END OF EJS Templates
Add -f flag to %history to direct output to file
fperez -
Show More

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

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