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