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