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