##// END OF EJS Templates
reintroduce recall magic
Matthias BUSSONNIER -
Show More
@@ -1,294 +1,301 b''
1 1 """Implementation of magic functions related to History.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2012, IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 16 # Stdlib
17 17 import os
18 18 from io import open as io_open
19 19
20 20 # Our own packages
21 21 from IPython.core.error import StdinNotImplementedError
22 22 from IPython.core.magic import Magics, magics_class, line_magic
23 23 from IPython.testing.skipdoctest import skip_doctest
24 24 from IPython.utils import io
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Magics class implementation
28 28 #-----------------------------------------------------------------------------
29 29
30 30 @magics_class
31 31 class HistoryMagics(Magics):
32 32
33 33 @skip_doctest
34 34 @line_magic
35 35 def history(self, parameter_s = ''):
36 36 """Print input history (_i<n> variables), with most recent last.
37 37
38 38 %history [-o -p -t -n] [-f filename] [range | -g pattern | -l number]
39 39
40 40 By default, input history is printed without line numbers so it can be
41 41 directly pasted into an editor. Use -n to show them.
42 42
43 43 By default, all input history from the current session is displayed.
44 44 Ranges of history can be indicated using the syntax:
45 45 4 : Line 4, current session
46 46 4-6 : Lines 4-6, current session
47 47 243/1-5: Lines 1-5, session 243
48 48 ~2/7 : Line 7, session 2 before current
49 49 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
50 50 of 6 sessions ago.
51 51 Multiple ranges can be entered, separated by spaces
52 52
53 53 The same syntax is used by %macro, %save, %edit, %rerun
54 54
55 55 Options:
56 56
57 57 -n: print line numbers for each input.
58 58 This feature is only available if numbered prompts are in use.
59 59
60 60 -o: also print outputs for each input.
61 61
62 62 -p: print classic '>>>' python prompts before each input. This is
63 63 useful for making documentation, and in conjunction with -o, for
64 64 producing doctest-ready output.
65 65
66 66 -r: (default) print the 'raw' history, i.e. the actual commands you
67 67 typed.
68 68
69 69 -t: print the 'translated' history, as IPython understands it.
70 70 IPython filters your input and converts it all into valid Python
71 71 source before executing it (things like magics or aliases are turned
72 72 into function calls, for example). With this option, you'll see the
73 73 native history instead of the user-entered version: '%cd /' will be
74 74 seen as 'get_ipython().magic("%cd /")' instead of '%cd /'.
75 75
76 76 -g: treat the arg as a pattern to grep for in (full) history.
77 77 This includes the saved history (almost all commands ever written).
78 78 Use '%hist -g' to show full saved history (may be very long).
79 79
80 80 -l: get the last n lines from all sessions. Specify n as a single
81 81 arg, or the default is the last 10 lines.
82 82
83 83 -f FILENAME: instead of printing the output to the screen, redirect
84 84 it to the given file. The file is always overwritten, though *when
85 85 it can*, IPython asks for confirmation first. In particular, running
86 86 the command 'history -f FILENAME' from the IPython Notebook
87 87 interface will replace FILENAME even if it already exists *without*
88 88 confirmation.
89 89
90 90 Examples
91 91 --------
92 92 ::
93 93
94 94 In [6]: %hist -n 4-6
95 95 4:a = 12
96 96 5:print a**2
97 97 6:%hist -n 4-6
98 98
99 99 """
100 100
101 101 if not self.shell.displayhook.do_full_cache:
102 102 print('This feature is only available if numbered prompts '
103 103 'are in use.')
104 104 return
105 105 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
106 106
107 107 # For brevity
108 108 history_manager = self.shell.history_manager
109 109
110 110 def _format_lineno(session, line):
111 111 """Helper function to format line numbers properly."""
112 112 if session in (0, history_manager.session_number):
113 113 return str(line)
114 114 return "%s/%s" % (session, line)
115 115
116 116 # Check if output to specific file was requested.
117 117 try:
118 118 outfname = opts['f']
119 119 except KeyError:
120 120 outfile = io.stdout # default
121 121 # We don't want to close stdout at the end!
122 122 close_at_end = False
123 123 else:
124 124 if os.path.exists(outfname):
125 125 try:
126 126 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
127 127 except StdinNotImplementedError:
128 128 ans = True
129 129 if not ans:
130 130 print('Aborting.')
131 131 return
132 132 print("Overwriting file.")
133 133 outfile = io_open(outfname, 'w', encoding='utf-8')
134 134 close_at_end = True
135 135
136 136 print_nums = 'n' in opts
137 137 get_output = 'o' in opts
138 138 pyprompts = 'p' in opts
139 139 # Raw history is the default
140 140 raw = not('t' in opts)
141 141
142 142 pattern = None
143 143
144 144 if 'g' in opts: # Glob search
145 145 pattern = "*" + args + "*" if args else "*"
146 146 hist = history_manager.search(pattern, raw=raw, output=get_output)
147 147 print_nums = True
148 148 elif 'l' in opts: # Get 'tail'
149 149 try:
150 150 n = int(args)
151 151 except (ValueError, IndexError):
152 152 n = 10
153 153 hist = history_manager.get_tail(n, raw=raw, output=get_output)
154 154 else:
155 155 if args: # Get history by ranges
156 156 hist = history_manager.get_range_by_str(args, raw, get_output)
157 157 else: # Just get history for the current session
158 158 hist = history_manager.get_range(raw=raw, output=get_output)
159 159
160 160 # We could be displaying the entire history, so let's not try to pull
161 161 # it into a list in memory. Anything that needs more space will just
162 162 # misalign.
163 163 width = 4
164 164
165 165 for session, lineno, inline in hist:
166 166 # Print user history with tabs expanded to 4 spaces. The GUI
167 167 # clients use hard tabs for easier usability in auto-indented code,
168 168 # but we want to produce PEP-8 compliant history for safe pasting
169 169 # into an editor.
170 170 if get_output:
171 171 inline, output = inline
172 172 inline = inline.expandtabs(4).rstrip()
173 173
174 174 multiline = "\n" in inline
175 175 line_sep = '\n' if multiline else ' '
176 176 if print_nums:
177 177 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
178 178 line_sep), file=outfile, end=u'')
179 179 if pyprompts:
180 180 print(u">>> ", end=u"", file=outfile)
181 181 if multiline:
182 182 inline = "\n... ".join(inline.splitlines()) + "\n..."
183 183 print(inline, file=outfile)
184 184 if get_output and output:
185 185 print(output, file=outfile)
186 186
187 187 if close_at_end:
188 188 outfile.close()
189 189
190 190 # For a long time we've had %hist as well as %history
191 191 @line_magic
192 192 def hist(self, arg):
193 193 return self.history(arg)
194 194
195 195 hist.__doc__ = history.__doc__
196 196
197 197 @line_magic
198 198 def rep(self, arg):
199 199 r"""Repeat a command, or get command to input line for editing.
200 200
201 201 %recall and %rep are equivalent.
202 202
203 203 - %recall (no arguments):
204 204
205 205 Place a string version of last computation result (stored in the
206 206 special '_' variable) to the next input prompt. Allows you to create
207 207 elaborate command lines without using copy-paste::
208 208
209 209 In[1]: l = ["hei", "vaan"]
210 210 In[2]: "".join(l)
211 211 Out[2]: heivaan
212 212 In[3]: %rep
213 213 In[4]: heivaan_ <== cursor blinking
214 214
215 215 %recall 45
216 216
217 217 Place history line 45 on the next input prompt. Use %hist to find
218 218 out the number.
219 219
220 220 %recall 1-4
221 221
222 222 Combine the specified lines into one cell, and place it on the next
223 223 input prompt. See %history for the slice syntax.
224 224
225 225 %recall foo+bar
226 226
227 227 If foo+bar can be evaluated in the user namespace, the result is
228 228 placed at the next input prompt. Otherwise, the history is searched
229 229 for lines which contain that substring, and the most recent one is
230 230 placed at the next input prompt.
231 231 """
232 232 if not arg: # Last output
233 233 self.shell.set_next_input(str(self.shell.user_ns["_"]))
234 234 return
235 235 # Get history range
236 236 histlines = self.shell.history_manager.get_range_by_str(arg)
237 237 cmd = "\n".join(x[2] for x in histlines)
238 238 if cmd:
239 239 self.shell.set_next_input(cmd.rstrip())
240 240 return
241 241
242 242 try: # Variable in user namespace
243 243 cmd = str(eval(arg, self.shell.user_ns))
244 244 except Exception: # Search for term in history
245 245 histlines = self.shell.history_manager.search("*"+arg+"*")
246 246 for h in reversed([x[2] for x in histlines]):
247 247 if 'rep' in h:
248 248 continue
249 249 self.shell.set_next_input(h.rstrip())
250 250 return
251 251 else:
252 252 self.shell.set_next_input(cmd.rstrip())
253 253 print("Couldn't evaluate or find in history:", arg)
254 254
255 255 @line_magic
256 256 def rerun(self, parameter_s=''):
257 257 """Re-run previous input
258 258
259 259 By default, you can specify ranges of input history to be repeated
260 260 (as with %history). With no arguments, it will repeat the last line.
261 261
262 262 Options:
263 263
264 264 -l <n> : Repeat the last n lines of input, not including the
265 265 current command.
266 266
267 267 -g foo : Repeat the most recent line which contains foo
268 268 """
269 269 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
270 270 if "l" in opts: # Last n lines
271 271 n = int(opts['l'])
272 272 hist = self.shell.history_manager.get_tail(n)
273 273 elif "g" in opts: # Search
274 274 p = "*"+opts['g']+"*"
275 275 hist = list(self.shell.history_manager.search(p))
276 276 for l in reversed(hist):
277 277 if "rerun" not in l[2]:
278 278 hist = [l] # The last match which isn't a %rerun
279 279 break
280 280 else:
281 281 hist = [] # No matches except %rerun
282 282 elif args: # Specify history ranges
283 283 hist = self.shell.history_manager.get_range_by_str(args)
284 284 else: # Last line
285 285 hist = self.shell.history_manager.get_tail(1)
286 286 hist = [x[2] for x in hist]
287 287 if not hist:
288 288 print("No lines in history match specification")
289 289 return
290 290 histlines = "\n".join(hist)
291 291 print("=== Executing: ===")
292 292 print(histlines)
293 293 print("=== Output: ===")
294 294 self.shell.run_cell("\n".join(hist), store_history=False)
295
296 @line_magic
297 def recall(self,arg):
298 self.rerun(arg)
299
300 recall.__doc__ = rerun.__doc__
301
General Comments 0
You need to be logged in to leave comments. Login now