##// END OF EJS Templates
Wrote example for %history...
Vishnu S G -
Show More
@@ -1,578 +1,588 b''
1 """ History related magics and functionality """
1 """ History related magics and functionality """
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (C) 2010 The IPython Development Team.
3 # Copyright (C) 2010 The IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the BSD License.
5 # Distributed under the terms of the BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 # Stdlib imports
15 # Stdlib imports
16 import atexit
16 import atexit
17 import fnmatch
17 import fnmatch
18 import json
18 import json
19 import os
19 import os
20 import sys
20 import sys
21 import threading
21 import threading
22 import time
22 import time
23
23
24 # Our own packages
24 # Our own packages
25 import IPython.utils.io
25 import IPython.utils.io
26
26
27 from IPython.utils.pickleshare import PickleShareDB
27 from IPython.utils.pickleshare import PickleShareDB
28 from IPython.utils.io import ask_yes_no
28 from IPython.utils.io import ask_yes_no
29 from IPython.utils.warn import warn
29 from IPython.utils.warn import warn
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # Classes and functions
32 # Classes and functions
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35 class HistoryManager(object):
35 class HistoryManager(object):
36 """A class to organize all history-related functionality in one place.
36 """A class to organize all history-related functionality in one place.
37 """
37 """
38 # Public interface
38 # Public interface
39
39
40 # An instance of the IPython shell we are attached to
40 # An instance of the IPython shell we are attached to
41 shell = None
41 shell = None
42 # A list to hold processed history
42 # A list to hold processed history
43 input_hist_parsed = None
43 input_hist_parsed = None
44 # A list to hold raw history (as typed by user)
44 # A list to hold raw history (as typed by user)
45 input_hist_raw = None
45 input_hist_raw = None
46 # A list of directories visited during session
46 # A list of directories visited during session
47 dir_hist = None
47 dir_hist = None
48 # A dict of output history, keyed with ints from the shell's execution count
48 # A dict of output history, keyed with ints from the shell's execution count
49 output_hist = None
49 output_hist = None
50 # String with path to the history file
50 # String with path to the history file
51 hist_file = None
51 hist_file = None
52 # PickleShareDB instance holding the raw data for the shadow history
52 # PickleShareDB instance holding the raw data for the shadow history
53 shadow_db = None
53 shadow_db = None
54 # ShadowHist instance with the actual shadow history
54 # ShadowHist instance with the actual shadow history
55 shadow_hist = None
55 shadow_hist = None
56
56
57 # Private interface
57 # Private interface
58 # Variables used to store the three last inputs from the user. On each new
58 # Variables used to store the three last inputs from the user. On each new
59 # history update, we populate the user's namespace with these, shifted as
59 # history update, we populate the user's namespace with these, shifted as
60 # necessary.
60 # necessary.
61 _i00, _i, _ii, _iii = '','','',''
61 _i00, _i, _ii, _iii = '','','',''
62
62
63 # A set with all forms of the exit command, so that we don't store them in
63 # A set with all forms of the exit command, so that we don't store them in
64 # the history (it's annoying to rewind the first entry and land on an exit
64 # the history (it's annoying to rewind the first entry and land on an exit
65 # call).
65 # call).
66 _exit_commands = None
66 _exit_commands = None
67
67
68 def __init__(self, shell):
68 def __init__(self, shell):
69 """Create a new history manager associated with a shell instance.
69 """Create a new history manager associated with a shell instance.
70 """
70 """
71 # We need a pointer back to the shell for various tasks.
71 # We need a pointer back to the shell for various tasks.
72 self.shell = shell
72 self.shell = shell
73
73
74 # List of input with multi-line handling.
74 # List of input with multi-line handling.
75 self.input_hist_parsed = []
75 self.input_hist_parsed = []
76 # This one will hold the 'raw' input history, without any
76 # This one will hold the 'raw' input history, without any
77 # pre-processing. This will allow users to retrieve the input just as
77 # pre-processing. This will allow users to retrieve the input just as
78 # it was exactly typed in by the user, with %hist -r.
78 # it was exactly typed in by the user, with %hist -r.
79 self.input_hist_raw = []
79 self.input_hist_raw = []
80
80
81 # list of visited directories
81 # list of visited directories
82 try:
82 try:
83 self.dir_hist = [os.getcwd()]
83 self.dir_hist = [os.getcwd()]
84 except OSError:
84 except OSError:
85 self.dir_hist = []
85 self.dir_hist = []
86
86
87 # dict of output history
87 # dict of output history
88 self.output_hist = {}
88 self.output_hist = {}
89
89
90 # Now the history file
90 # Now the history file
91 if shell.profile:
91 if shell.profile:
92 histfname = 'history-%s' % shell.profile
92 histfname = 'history-%s' % shell.profile
93 else:
93 else:
94 histfname = 'history'
94 histfname = 'history'
95 self.hist_file = os.path.join(shell.ipython_dir, histfname + '.json')
95 self.hist_file = os.path.join(shell.ipython_dir, histfname + '.json')
96
96
97 # Objects related to shadow history management
97 # Objects related to shadow history management
98 self._init_shadow_hist()
98 self._init_shadow_hist()
99
99
100 self._i00, self._i, self._ii, self._iii = '','','',''
100 self._i00, self._i, self._ii, self._iii = '','','',''
101
101
102 self._exit_commands = set(['Quit', 'quit', 'Exit', 'exit', '%Quit',
102 self._exit_commands = set(['Quit', 'quit', 'Exit', 'exit', '%Quit',
103 '%quit', '%Exit', '%exit'])
103 '%quit', '%Exit', '%exit'])
104
104
105 # Object is fully initialized, we can now call methods on it.
105 # Object is fully initialized, we can now call methods on it.
106
106
107 # Fill the history zero entry, user counter starts at 1
107 # Fill the history zero entry, user counter starts at 1
108 self.store_inputs('\n', '\n')
108 self.store_inputs('\n', '\n')
109
109
110 # Create and start the autosaver.
110 # Create and start the autosaver.
111 self.autosave_flag = threading.Event()
111 self.autosave_flag = threading.Event()
112 self.autosave_timer = HistorySaveThread(self.autosave_flag, 60)
112 self.autosave_timer = HistorySaveThread(self.autosave_flag, 60)
113 self.autosave_timer.start()
113 self.autosave_timer.start()
114 # Register the autosave handler to be triggered as a post execute
114 # Register the autosave handler to be triggered as a post execute
115 # callback.
115 # callback.
116 self.shell.register_post_execute(self.autosave_if_due)
116 self.shell.register_post_execute(self.autosave_if_due)
117
117
118 def _init_shadow_hist(self):
118 def _init_shadow_hist(self):
119 try:
119 try:
120 self.shadow_db = PickleShareDB(os.path.join(
120 self.shadow_db = PickleShareDB(os.path.join(
121 self.shell.ipython_dir, 'db'))
121 self.shell.ipython_dir, 'db'))
122 except UnicodeDecodeError:
122 except UnicodeDecodeError:
123 print("Your ipython_dir can't be decoded to unicode!")
123 print("Your ipython_dir can't be decoded to unicode!")
124 print("Please set HOME environment variable to something that")
124 print("Please set HOME environment variable to something that")
125 print(r"only has ASCII characters, e.g. c:\home")
125 print(r"only has ASCII characters, e.g. c:\home")
126 print("Now it is", self.ipython_dir)
126 print("Now it is", self.ipython_dir)
127 sys.exit()
127 sys.exit()
128 self.shadow_hist = ShadowHist(self.shadow_db, self.shell)
128 self.shadow_hist = ShadowHist(self.shadow_db, self.shell)
129
129
130 def populate_readline_history(self):
130 def populate_readline_history(self):
131 """Populate the readline history from the raw history.
131 """Populate the readline history from the raw history.
132
132
133 We only store one copy of the raw history, which is persisted to a json
133 We only store one copy of the raw history, which is persisted to a json
134 file on disk. The readline history is repopulated from the contents of
134 file on disk. The readline history is repopulated from the contents of
135 this file."""
135 this file."""
136
136
137 try:
137 try:
138 self.shell.readline.clear_history()
138 self.shell.readline.clear_history()
139 except AttributeError:
139 except AttributeError:
140 pass
140 pass
141 else:
141 else:
142 for h in self.input_hist_raw:
142 for h in self.input_hist_raw:
143 if not h.isspace():
143 if not h.isspace():
144 for line in h.splitlines():
144 for line in h.splitlines():
145 self.shell.readline.add_history(line)
145 self.shell.readline.add_history(line)
146
146
147 def save_history(self):
147 def save_history(self):
148 """Save input history to a file (via readline library)."""
148 """Save input history to a file (via readline library)."""
149 hist = dict(raw=self.input_hist_raw, #[-self.shell.history_length:],
149 hist = dict(raw=self.input_hist_raw, #[-self.shell.history_length:],
150 parsed=self.input_hist_parsed) #[-self.shell.history_length:])
150 parsed=self.input_hist_parsed) #[-self.shell.history_length:])
151 with open(self.hist_file,'wt') as hfile:
151 with open(self.hist_file,'wt') as hfile:
152 json.dump(hist, hfile,
152 json.dump(hist, hfile,
153 sort_keys=True, indent=4)
153 sort_keys=True, indent=4)
154
154
155 def autosave_if_due(self):
155 def autosave_if_due(self):
156 """Check if the autosave event is set; if so, save history. We do it
156 """Check if the autosave event is set; if so, save history. We do it
157 this way so that the save takes place in the main thread."""
157 this way so that the save takes place in the main thread."""
158 if self.autosave_flag.is_set():
158 if self.autosave_flag.is_set():
159 self.save_history()
159 self.save_history()
160 self.autosave_flag.clear()
160 self.autosave_flag.clear()
161
161
162 def reload_history(self):
162 def reload_history(self):
163 """Reload the input history from disk file."""
163 """Reload the input history from disk file."""
164
164
165 with open(self.hist_file,'rt') as hfile:
165 with open(self.hist_file,'rt') as hfile:
166 try:
166 try:
167 hist = json.load(hfile)
167 hist = json.load(hfile)
168 except ValueError: # Ignore it if JSON is corrupt.
168 except ValueError: # Ignore it if JSON is corrupt.
169 return
169 return
170 self.input_hist_parsed = hist['parsed']
170 self.input_hist_parsed = hist['parsed']
171 self.input_hist_raw = hist['raw']
171 self.input_hist_raw = hist['raw']
172 if self.shell.has_readline:
172 if self.shell.has_readline:
173 self.populate_readline_history()
173 self.populate_readline_history()
174
174
175 def get_history(self, index=None, raw=False, output=True):
175 def get_history(self, index=None, raw=False, output=True):
176 """Get the history list.
176 """Get the history list.
177
177
178 Get the input and output history.
178 Get the input and output history.
179
179
180 Parameters
180 Parameters
181 ----------
181 ----------
182 index : n or (n1, n2) or None
182 index : n or (n1, n2) or None
183 If n, then the last entries. If a tuple, then all in
183 If n, then the last entries. If a tuple, then all in
184 range(n1, n2). If None, then all entries. Raises IndexError if
184 range(n1, n2). If None, then all entries. Raises IndexError if
185 the format of index is incorrect.
185 the format of index is incorrect.
186 raw : bool
186 raw : bool
187 If True, return the raw input.
187 If True, return the raw input.
188 output : bool
188 output : bool
189 If True, then return the output as well.
189 If True, then return the output as well.
190
190
191 Returns
191 Returns
192 -------
192 -------
193 If output is True, then return a dict of tuples, keyed by the prompt
193 If output is True, then return a dict of tuples, keyed by the prompt
194 numbers and with values of (input, output). If output is False, then
194 numbers and with values of (input, output). If output is False, then
195 a dict, keyed by the prompt number with the values of input. Raises
195 a dict, keyed by the prompt number with the values of input. Raises
196 IndexError if no history is found.
196 IndexError if no history is found.
197 """
197 """
198 if raw:
198 if raw:
199 input_hist = self.input_hist_raw
199 input_hist = self.input_hist_raw
200 else:
200 else:
201 input_hist = self.input_hist_parsed
201 input_hist = self.input_hist_parsed
202 if output:
202 if output:
203 output_hist = self.output_hist
203 output_hist = self.output_hist
204 n = len(input_hist)
204 n = len(input_hist)
205 if index is None:
205 if index is None:
206 start=0; stop=n
206 start=0; stop=n
207 elif isinstance(index, int):
207 elif isinstance(index, int):
208 start=n-index; stop=n
208 start=n-index; stop=n
209 elif isinstance(index, tuple) and len(index) == 2:
209 elif isinstance(index, tuple) and len(index) == 2:
210 start=index[0]; stop=index[1]
210 start=index[0]; stop=index[1]
211 else:
211 else:
212 raise IndexError('Not a valid index for the input history: %r'
212 raise IndexError('Not a valid index for the input history: %r'
213 % index)
213 % index)
214 hist = {}
214 hist = {}
215 for i in range(start, stop):
215 for i in range(start, stop):
216 if output:
216 if output:
217 hist[i] = (input_hist[i], output_hist.get(i))
217 hist[i] = (input_hist[i], output_hist.get(i))
218 else:
218 else:
219 hist[i] = input_hist[i]
219 hist[i] = input_hist[i]
220 if not hist:
220 if not hist:
221 raise IndexError('No history for range of indices: %r' % index)
221 raise IndexError('No history for range of indices: %r' % index)
222 return hist
222 return hist
223
223
224 def store_inputs(self, source, source_raw=None):
224 def store_inputs(self, source, source_raw=None):
225 """Store source and raw input in history and create input cache
225 """Store source and raw input in history and create input cache
226 variables _i*.
226 variables _i*.
227
227
228 Parameters
228 Parameters
229 ----------
229 ----------
230 source : str
230 source : str
231 Python input.
231 Python input.
232
232
233 source_raw : str, optional
233 source_raw : str, optional
234 If given, this is the raw input without any IPython transformations
234 If given, this is the raw input without any IPython transformations
235 applied to it. If not given, ``source`` is used.
235 applied to it. If not given, ``source`` is used.
236 """
236 """
237 if source_raw is None:
237 if source_raw is None:
238 source_raw = source
238 source_raw = source
239
239
240 # do not store exit/quit commands
240 # do not store exit/quit commands
241 if source_raw.strip() in self._exit_commands:
241 if source_raw.strip() in self._exit_commands:
242 return
242 return
243
243
244 self.input_hist_parsed.append(source.rstrip())
244 self.input_hist_parsed.append(source.rstrip())
245 self.input_hist_raw.append(source_raw.rstrip())
245 self.input_hist_raw.append(source_raw.rstrip())
246 self.shadow_hist.add(source)
246 self.shadow_hist.add(source)
247
247
248 # update the auto _i variables
248 # update the auto _i variables
249 self._iii = self._ii
249 self._iii = self._ii
250 self._ii = self._i
250 self._ii = self._i
251 self._i = self._i00
251 self._i = self._i00
252 self._i00 = source_raw
252 self._i00 = source_raw
253
253
254 # hackish access to user namespace to create _i1,_i2... dynamically
254 # hackish access to user namespace to create _i1,_i2... dynamically
255 new_i = '_i%s' % self.shell.execution_count
255 new_i = '_i%s' % self.shell.execution_count
256 to_main = {'_i': self._i,
256 to_main = {'_i': self._i,
257 '_ii': self._ii,
257 '_ii': self._ii,
258 '_iii': self._iii,
258 '_iii': self._iii,
259 new_i : self._i00 }
259 new_i : self._i00 }
260 self.shell.user_ns.update(to_main)
260 self.shell.user_ns.update(to_main)
261
261
262 def sync_inputs(self):
262 def sync_inputs(self):
263 """Ensure raw and translated histories have same length."""
263 """Ensure raw and translated histories have same length."""
264 if len(self.input_hist_parsed) != len (self.input_hist_raw):
264 if len(self.input_hist_parsed) != len (self.input_hist_raw):
265 self.input_hist_raw[:] = self.input_hist_parsed
265 self.input_hist_raw[:] = self.input_hist_parsed
266
266
267 def reset(self):
267 def reset(self):
268 """Clear all histories managed by this object."""
268 """Clear all histories managed by this object."""
269 self.input_hist_parsed[:] = []
269 self.input_hist_parsed[:] = []
270 self.input_hist_raw[:] = []
270 self.input_hist_raw[:] = []
271 self.output_hist.clear()
271 self.output_hist.clear()
272 # The directory history can't be completely empty
272 # The directory history can't be completely empty
273 self.dir_hist[:] = [os.getcwd()]
273 self.dir_hist[:] = [os.getcwd()]
274
274
275 class HistorySaveThread(threading.Thread):
275 class HistorySaveThread(threading.Thread):
276 """This thread makes IPython save history periodically.
276 """This thread makes IPython save history periodically.
277
277
278 Without this class, IPython would only save the history on a clean exit.
278 Without this class, IPython would only save the history on a clean exit.
279 This saves the history periodically (the current default is once per
279 This saves the history periodically (the current default is once per
280 minute), so that it is not lost in the event of a crash.
280 minute), so that it is not lost in the event of a crash.
281
281
282 The implementation sets an event to indicate that history should be saved.
282 The implementation sets an event to indicate that history should be saved.
283 The actual save is carried out after executing a user command, to avoid
283 The actual save is carried out after executing a user command, to avoid
284 thread issues.
284 thread issues.
285 """
285 """
286 daemon = True
286 daemon = True
287
287
288 def __init__(self, autosave_flag, time_interval=60):
288 def __init__(self, autosave_flag, time_interval=60):
289 threading.Thread.__init__(self)
289 threading.Thread.__init__(self)
290 self.time_interval = time_interval
290 self.time_interval = time_interval
291 self.autosave_flag = autosave_flag
291 self.autosave_flag = autosave_flag
292 self.exit_now = threading.Event()
292 self.exit_now = threading.Event()
293 # Ensure the thread is stopped tidily when exiting normally
293 # Ensure the thread is stopped tidily when exiting normally
294 atexit.register(self.stop)
294 atexit.register(self.stop)
295
295
296 def run(self):
296 def run(self):
297 while True:
297 while True:
298 self.exit_now.wait(self.time_interval)
298 self.exit_now.wait(self.time_interval)
299 if self.exit_now.is_set():
299 if self.exit_now.is_set():
300 break
300 break
301 self.autosave_flag.set()
301 self.autosave_flag.set()
302
302
303 def stop(self):
303 def stop(self):
304 """Safely and quickly stop the autosave timer thread."""
304 """Safely and quickly stop the autosave timer thread."""
305 self.exit_now.set()
305 self.exit_now.set()
306 self.join()
306 self.join()
307
307
308 def magic_history(self, parameter_s = ''):
308 def magic_history(self, parameter_s = ''):
309 """Print input history (_i<n> variables), with most recent last.
309 """Print input history (_i<n> variables), with most recent last.
310
310
311 %history -> print at most 40 inputs (some may be multi-line)\\
311 %history -> print at most 40 inputs (some may be multi-line)\\
312 %history n -> print at most n inputs\\
312 %history n -> print at most n inputs\\
313 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
313 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
314
314
315 By default, input history is printed without line numbers so it can be
315 By default, input history is printed without line numbers so it can be
316 directly pasted into an editor.
316 directly pasted into an editor.
317
317
318 With -n, each input's number <n> is shown, and is accessible as the
318 With -n, each input's number <n> is shown, and is accessible as the
319 automatically generated variable _i<n> as well as In[<n>]. Multi-line
319 automatically generated variable _i<n> as well as In[<n>]. Multi-line
320 statements are printed starting at a new line for easy copy/paste.
320 statements are printed starting at a new line for easy copy/paste.
321
321
322 Options:
322 Options:
323
323
324 -n: print line numbers for each input.
324 -n: print line numbers for each input.
325 This feature is only available if numbered prompts are in use.
325 This feature is only available if numbered prompts are in use.
326
326
327 -o: also print outputs for each input.
327 -o: also print outputs for each input.
328
328
329 -p: print classic '>>>' python prompts before each input. This is useful
329 -p: print classic '>>>' python prompts before each input. This is useful
330 for making documentation, and in conjunction with -o, for producing
330 for making documentation, and in conjunction with -o, for producing
331 doctest-ready output.
331 doctest-ready output.
332
332
333 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
333 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
334
334
335 -t: print the 'translated' history, as IPython understands it. IPython
335 -t: print the 'translated' history, as IPython understands it. IPython
336 filters your input and converts it all into valid Python source before
336 filters your input and converts it all into valid Python source before
337 executing it (things like magics or aliases are turned into function
337 executing it (things like magics or aliases are turned into function
338 calls, for example). With this option, you'll see the native history
338 calls, for example). With this option, you'll see the native history
339 instead of the user-entered version: '%cd /' will be seen as
339 instead of the user-entered version: '%cd /' will be seen as
340 'get_ipython().magic("%cd /")' instead of '%cd /'.
340 'get_ipython().magic("%cd /")' instead of '%cd /'.
341
341
342 -g: treat the arg as a pattern to grep for in (full) history.
342 -g: treat the arg as a pattern to grep for in (full) history.
343 This includes the "shadow history" (almost all commands ever written).
343 This includes the "shadow history" (almost all commands ever written).
344 Use '%hist -g' to show full shadow history (may be very long).
344 Use '%hist -g' to show full shadow history (may be very long).
345 In shadow history, every index nuwber starts with 0.
345 In shadow history, every index nuwber starts with 0.
346
346
347 -f FILENAME: instead of printing the output to the screen, redirect it to
347 -f FILENAME: instead of printing the output to the screen, redirect it to
348 the given file. The file is always overwritten, though IPython asks for
348 the given file. The file is always overwritten, though IPython asks for
349 confirmation first if it already exists.
349 confirmation first if it already exists.
350
351 Example
352 -------
353
354 ::
355
356 In [6]: %hist -n 4 6
357 4:a = 12
358 5:print a**2
359
350 """
360 """
351
361
352 if not self.shell.displayhook.do_full_cache:
362 if not self.shell.displayhook.do_full_cache:
353 print('This feature is only available if numbered prompts are in use.')
363 print('This feature is only available if numbered prompts are in use.')
354 return
364 return
355 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
365 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
356
366
357 # Check if output to specific file was requested.
367 # Check if output to specific file was requested.
358 try:
368 try:
359 outfname = opts['f']
369 outfname = opts['f']
360 except KeyError:
370 except KeyError:
361 outfile = IPython.utils.io.Term.cout # default
371 outfile = IPython.utils.io.Term.cout # default
362 # We don't want to close stdout at the end!
372 # We don't want to close stdout at the end!
363 close_at_end = False
373 close_at_end = False
364 else:
374 else:
365 if os.path.exists(outfname):
375 if os.path.exists(outfname):
366 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
376 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
367 print('Aborting.')
377 print('Aborting.')
368 return
378 return
369
379
370 outfile = open(outfname,'w')
380 outfile = open(outfname,'w')
371 close_at_end = True
381 close_at_end = True
372
382
373 if 't' in opts:
383 if 't' in opts:
374 input_hist = self.shell.history_manager.input_hist_parsed
384 input_hist = self.shell.history_manager.input_hist_parsed
375 elif 'r' in opts:
385 elif 'r' in opts:
376 input_hist = self.shell.history_manager.input_hist_raw
386 input_hist = self.shell.history_manager.input_hist_raw
377 else:
387 else:
378 # Raw history is the default
388 # Raw history is the default
379 input_hist = self.shell.history_manager.input_hist_raw
389 input_hist = self.shell.history_manager.input_hist_raw
380
390
381 default_length = 40
391 default_length = 40
382 pattern = None
392 pattern = None
383 if 'g' in opts:
393 if 'g' in opts:
384 init = 1
394 init = 1
385 final = len(input_hist)
395 final = len(input_hist)
386 parts = parameter_s.split(None, 1)
396 parts = parameter_s.split(None, 1)
387 if len(parts) == 1:
397 if len(parts) == 1:
388 parts += '*'
398 parts += '*'
389 head, pattern = parts
399 head, pattern = parts
390 pattern = "*" + pattern + "*"
400 pattern = "*" + pattern + "*"
391 elif len(args) == 0:
401 elif len(args) == 0:
392 final = len(input_hist)-1
402 final = len(input_hist)-1
393 init = max(1,final-default_length)
403 init = max(1,final-default_length)
394 elif len(args) == 1:
404 elif len(args) == 1:
395 final = len(input_hist)
405 final = len(input_hist)
396 init = max(1, final-int(args[0]))
406 init = max(1, final-int(args[0]))
397 elif len(args) == 2:
407 elif len(args) == 2:
398 init, final = map(int, args)
408 init, final = map(int, args)
399 else:
409 else:
400 warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
410 warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
401 print(self.magic_hist.__doc__, file=IPython.utils.io.Term.cout)
411 print(self.magic_hist.__doc__, file=IPython.utils.io.Term.cout)
402 return
412 return
403
413
404 width = len(str(final))
414 width = len(str(final))
405 line_sep = ['','\n']
415 line_sep = ['','\n']
406 print_nums = 'n' in opts
416 print_nums = 'n' in opts
407 print_outputs = 'o' in opts
417 print_outputs = 'o' in opts
408 pyprompts = 'p' in opts
418 pyprompts = 'p' in opts
409
419
410 found = False
420 found = False
411 if pattern is not None:
421 if pattern is not None:
412 sh = self.shell.history_manager.shadowhist.all()
422 sh = self.shell.history_manager.shadowhist.all()
413 for idx, s in sh:
423 for idx, s in sh:
414 if fnmatch.fnmatch(s, pattern):
424 if fnmatch.fnmatch(s, pattern):
415 print("0%d: %s" %(idx, s.expandtabs(4)), file=outfile)
425 print("0%d: %s" %(idx, s.expandtabs(4)), file=outfile)
416 found = True
426 found = True
417
427
418 if found:
428 if found:
419 print("===", file=outfile)
429 print("===", file=outfile)
420 print("shadow history ends, fetch by %rep <number> (must start with 0)",
430 print("shadow history ends, fetch by %rep <number> (must start with 0)",
421 file=outfile)
431 file=outfile)
422 print("=== start of normal history ===", file=outfile)
432 print("=== start of normal history ===", file=outfile)
423
433
424 for in_num in range(init, final):
434 for in_num in range(init, final):
425 # Print user history with tabs expanded to 4 spaces. The GUI clients
435 # Print user history with tabs expanded to 4 spaces. The GUI clients
426 # use hard tabs for easier usability in auto-indented code, but we want
436 # use hard tabs for easier usability in auto-indented code, but we want
427 # to produce PEP-8 compliant history for safe pasting into an editor.
437 # to produce PEP-8 compliant history for safe pasting into an editor.
428 inline = input_hist[in_num].expandtabs(4).rstrip()+'\n'
438 inline = input_hist[in_num].expandtabs(4).rstrip()+'\n'
429
439
430 if pattern is not None and not fnmatch.fnmatch(inline, pattern):
440 if pattern is not None and not fnmatch.fnmatch(inline, pattern):
431 continue
441 continue
432
442
433 multiline = int(inline.count('\n') > 1)
443 multiline = int(inline.count('\n') > 1)
434 if print_nums:
444 if print_nums:
435 print('%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
445 print('%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
436 file=outfile)
446 file=outfile)
437 if pyprompts:
447 if pyprompts:
438 print('>>>', file=outfile)
448 print('>>>', file=outfile)
439 if multiline:
449 if multiline:
440 lines = inline.splitlines()
450 lines = inline.splitlines()
441 print('\n... '.join(lines), file=outfile)
451 print('\n... '.join(lines), file=outfile)
442 print('... ', file=outfile)
452 print('... ', file=outfile)
443 else:
453 else:
444 print(inline, end='', file=outfile)
454 print(inline, end='', file=outfile)
445 else:
455 else:
446 print(inline, end='', file=outfile)
456 print(inline, end='', file=outfile)
447 if print_outputs:
457 if print_outputs:
448 output = self.shell.history_manager.output_hist.get(in_num)
458 output = self.shell.history_manager.output_hist.get(in_num)
449 if output is not None:
459 if output is not None:
450 print(repr(output), file=outfile)
460 print(repr(output), file=outfile)
451
461
452 if close_at_end:
462 if close_at_end:
453 outfile.close()
463 outfile.close()
454
464
455
465
456 def magic_hist(self, parameter_s=''):
466 def magic_hist(self, parameter_s=''):
457 """Alternate name for %history."""
467 """Alternate name for %history."""
458 return self.magic_history(parameter_s)
468 return self.magic_history(parameter_s)
459
469
460
470
461 def rep_f(self, arg):
471 def rep_f(self, arg):
462 r""" Repeat a command, or get command to input line for editing
472 r""" Repeat a command, or get command to input line for editing
463
473
464 - %rep (no arguments):
474 - %rep (no arguments):
465
475
466 Place a string version of last computation result (stored in the special '_'
476 Place a string version of last computation result (stored in the special '_'
467 variable) to the next input prompt. Allows you to create elaborate command
477 variable) to the next input prompt. Allows you to create elaborate command
468 lines without using copy-paste::
478 lines without using copy-paste::
469
479
470 $ l = ["hei", "vaan"]
480 $ l = ["hei", "vaan"]
471 $ "".join(l)
481 $ "".join(l)
472 ==> heivaan
482 ==> heivaan
473 $ %rep
483 $ %rep
474 $ heivaan_ <== cursor blinking
484 $ heivaan_ <== cursor blinking
475
485
476 %rep 45
486 %rep 45
477
487
478 Place history line 45 to next input prompt. Use %hist to find out the
488 Place history line 45 to next input prompt. Use %hist to find out the
479 number.
489 number.
480
490
481 %rep 1-4 6-7 3
491 %rep 1-4 6-7 3
482
492
483 Repeat the specified lines immediately. Input slice syntax is the same as
493 Repeat the specified lines immediately. Input slice syntax is the same as
484 in %macro and %save.
494 in %macro and %save.
485
495
486 %rep foo
496 %rep foo
487
497
488 Place the most recent line that has the substring "foo" to next input.
498 Place the most recent line that has the substring "foo" to next input.
489 (e.g. 'svn ci -m foobar').
499 (e.g. 'svn ci -m foobar').
490 """
500 """
491
501
492 opts,args = self.parse_options(arg,'',mode='list')
502 opts,args = self.parse_options(arg,'',mode='list')
493 if not args:
503 if not args:
494 self.set_next_input(str(self.shell.user_ns["_"]))
504 self.set_next_input(str(self.shell.user_ns["_"]))
495 return
505 return
496
506
497 if len(args) == 1 and not '-' in args[0]:
507 if len(args) == 1 and not '-' in args[0]:
498 arg = args[0]
508 arg = args[0]
499 if len(arg) > 1 and arg.startswith('0'):
509 if len(arg) > 1 and arg.startswith('0'):
500 # get from shadow hist
510 # get from shadow hist
501 num = int(arg[1:])
511 num = int(arg[1:])
502 line = self.shell.shadowhist.get(num)
512 line = self.shell.shadowhist.get(num)
503 self.set_next_input(str(line))
513 self.set_next_input(str(line))
504 return
514 return
505 try:
515 try:
506 num = int(args[0])
516 num = int(args[0])
507 self.set_next_input(str(self.shell.input_hist_raw[num]).rstrip())
517 self.set_next_input(str(self.shell.input_hist_raw[num]).rstrip())
508 return
518 return
509 except ValueError:
519 except ValueError:
510 pass
520 pass
511
521
512 for h in reversed(self.shell.input_hist_raw):
522 for h in reversed(self.shell.input_hist_raw):
513 if 'rep' in h:
523 if 'rep' in h:
514 continue
524 continue
515 if fnmatch.fnmatch(h,'*' + arg + '*'):
525 if fnmatch.fnmatch(h,'*' + arg + '*'):
516 self.set_next_input(str(h).rstrip())
526 self.set_next_input(str(h).rstrip())
517 return
527 return
518
528
519 try:
529 try:
520 lines = self.extract_input_slices(args, True)
530 lines = self.extract_input_slices(args, True)
521 print("lines", lines)
531 print("lines", lines)
522 self.run_cell(lines)
532 self.run_cell(lines)
523 except ValueError:
533 except ValueError:
524 print("Not found in recent history:", args)
534 print("Not found in recent history:", args)
525
535
526
536
527 _sentinel = object()
537 _sentinel = object()
528
538
529 class ShadowHist(object):
539 class ShadowHist(object):
530 def __init__(self, db, shell):
540 def __init__(self, db, shell):
531 # cmd => idx mapping
541 # cmd => idx mapping
532 self.curidx = 0
542 self.curidx = 0
533 self.db = db
543 self.db = db
534 self.disabled = False
544 self.disabled = False
535 self.shell = shell
545 self.shell = shell
536
546
537 def inc_idx(self):
547 def inc_idx(self):
538 idx = self.db.get('shadowhist_idx', 1)
548 idx = self.db.get('shadowhist_idx', 1)
539 self.db['shadowhist_idx'] = idx + 1
549 self.db['shadowhist_idx'] = idx + 1
540 return idx
550 return idx
541
551
542 def add(self, ent):
552 def add(self, ent):
543 if self.disabled:
553 if self.disabled:
544 return
554 return
545 try:
555 try:
546 old = self.db.hget('shadowhist', ent, _sentinel)
556 old = self.db.hget('shadowhist', ent, _sentinel)
547 if old is not _sentinel:
557 if old is not _sentinel:
548 return
558 return
549 newidx = self.inc_idx()
559 newidx = self.inc_idx()
550 #print("new", newidx) # dbg
560 #print("new", newidx) # dbg
551 self.db.hset('shadowhist',ent, newidx)
561 self.db.hset('shadowhist',ent, newidx)
552 except:
562 except:
553 self.shell.showtraceback()
563 self.shell.showtraceback()
554 print("WARNING: disabling shadow history")
564 print("WARNING: disabling shadow history")
555 self.disabled = True
565 self.disabled = True
556
566
557 def all(self):
567 def all(self):
558 d = self.db.hdict('shadowhist')
568 d = self.db.hdict('shadowhist')
559 items = [(i,s) for (s,i) in d.iteritems()]
569 items = [(i,s) for (s,i) in d.iteritems()]
560 items.sort()
570 items.sort()
561 return items
571 return items
562
572
563 def get(self, idx):
573 def get(self, idx):
564 all = self.all()
574 all = self.all()
565
575
566 for k, v in all:
576 for k, v in all:
567 if k == idx:
577 if k == idx:
568 return v
578 return v
569
579
570
580
571 def init_ipython(ip):
581 def init_ipython(ip):
572 ip.define_magic("rep",rep_f)
582 ip.define_magic("rep",rep_f)
573 ip.define_magic("hist",magic_hist)
583 ip.define_magic("hist",magic_hist)
574 ip.define_magic("history",magic_history)
584 ip.define_magic("history",magic_history)
575
585
576 # XXX - ipy_completers are in quarantine, need to be updated to new apis
586 # XXX - ipy_completers are in quarantine, need to be updated to new apis
577 #import ipy_completers
587 #import ipy_completers
578 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
588 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
General Comments 0
You need to be logged in to leave comments. Login now