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