##// END OF EJS Templates
Reworking magic %hist, %macro and %edit commands to work with new history system.
Thomas Kluyver -
Show More
@@ -66,8 +66,11 b' class HistoryManager(object):'
66 66 # call).
67 67 _exit_commands = None
68 68
69 def __init__(self, shell):
69 def __init__(self, shell, load_history=False):
70 70 """Create a new history manager associated with a shell instance.
71
72 If load_history is true, it will load the history from file and set the
73 session offset so that the next line typed can be retrieved as #1.
71 74 """
72 75 # We need a pointer back to the shell for various tasks.
73 76 self.shell = shell
@@ -78,6 +81,9 b' class HistoryManager(object):'
78 81 # pre-processing. This will allow users to retrieve the input just as
79 82 # it was exactly typed in by the user, with %hist -r.
80 83 self.input_hist_raw = []
84
85 # Offset so the first line of the current session is #1
86 self.session_offset = -1
81 87
82 88 # list of visited directories
83 89 try:
@@ -105,8 +111,9 b' class HistoryManager(object):'
105 111
106 112 # Object is fully initialized, we can now call methods on it.
107 113
108 # Fill the history zero entry, user counter starts at 1
109 self.store_inputs('\n', '\n')
114 if load_history:
115 self.reload_history()
116 self.session_offset = len(self.input_hist_raw) -1
110 117
111 118 # Create and start the autosaver.
112 119 self.autosave_flag = threading.Event()
@@ -115,6 +122,7 b' class HistoryManager(object):'
115 122 # Register the autosave handler to be triggered as a post execute
116 123 # callback.
117 124 self.shell.register_post_execute(self.autosave_if_due)
125
118 126
119 127 def _init_shadow_hist(self):
120 128 try:
@@ -181,7 +189,7 b' class HistoryManager(object):'
181 189 Parameters
182 190 ----------
183 191 index : n or (n1, n2) or None
184 If n, then the last entries. If a tuple, then all in
192 If n, then the last n entries. If a tuple, then all in
185 193 range(n1, n2). If None, then all entries. Raises IndexError if
186 194 the format of index is incorrect.
187 195 raw : bool
@@ -193,8 +201,7 b' class HistoryManager(object):'
193 201 -------
194 202 If output is True, then return a dict of tuples, keyed by the prompt
195 203 numbers and with values of (input, output). If output is False, then
196 a dict, keyed by the prompt number with the values of input. Raises
197 IndexError if no history is found.
204 a dict, keyed by the prompt number with the values of input.
198 205 """
199 206 if raw:
200 207 input_hist = self.input_hist_raw
@@ -202,24 +209,25 b' class HistoryManager(object):'
202 209 input_hist = self.input_hist_parsed
203 210 if output:
204 211 output_hist = self.output_hist
212
205 213 n = len(input_hist)
214 offset = self.session_offset
206 215 if index is None:
207 start=0; stop=n
216 start=offset+1; stop=n
208 217 elif isinstance(index, int):
209 218 start=n-index; stop=n
210 elif isinstance(index, tuple) and len(index) == 2:
211 start=index[0]; stop=index[1]
219 elif len(index) == 2:
220 start = index[0] + offset
221 stop = index[1] + offset
212 222 else:
213 223 raise IndexError('Not a valid index for the input history: %r'
214 224 % index)
215 225 hist = {}
216 226 for i in range(start, stop):
217 227 if output:
218 hist[i] = (input_hist[i], output_hist.get(i))
228 hist[i-offset] = (input_hist[i], output_hist.get(i-offset))
219 229 else:
220 hist[i] = input_hist[i]
221 if not hist:
222 raise IndexError('No history for range of indices: %r' % index)
230 hist[i-offset] = input_hist[i]
223 231 return hist
224 232
225 233 def store_inputs(self, source, source_raw=None):
@@ -364,6 +372,9 b" def magic_history(self, parameter_s = ''):"
364 372 print('This feature is only available if numbered prompts are in use.')
365 373 return
366 374 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
375
376 # For brevity
377 history_manager = self.shell.history_manager
367 378
368 379 # Check if output to specific file was requested.
369 380 try:
@@ -380,47 +391,41 b" def magic_history(self, parameter_s = ''):"
380 391
381 392 outfile = open(outfname,'w')
382 393 close_at_end = True
383
384 if 't' in opts:
385 input_hist = self.shell.history_manager.input_hist_parsed
386 elif 'r' in opts:
387 input_hist = self.shell.history_manager.input_hist_raw
388 else:
389 # Raw history is the default
390 input_hist = self.shell.history_manager.input_hist_raw
394
395 print_nums = 'n' in opts
396 print_outputs = 'o' in opts
397 pyprompts = 'p' in opts
398 # Raw history is the default
399 raw = not('t' in opts)
391 400
392 401 default_length = 40
393 402 pattern = None
394 403 if 'g' in opts:
395 init = 1
396 final = len(input_hist)
404 index = None
397 405 parts = parameter_s.split(None, 1)
398 406 if len(parts) == 1:
399 407 parts += '*'
400 408 head, pattern = parts
401 409 pattern = "*" + pattern + "*"
402 410 elif len(args) == 0:
403 final = len(input_hist)-1
404 init = max(1,final-default_length)
411 index = None
405 412 elif len(args) == 1:
406 final = len(input_hist)
407 init = max(1, final-int(args[0]))
413 index = int(args[0])
408 414 elif len(args) == 2:
409 init, final = map(int, args)
415 index = map(int, args)
410 416 else:
411 417 warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
412 418 print(self.magic_hist.__doc__, file=IPython.utils.io.Term.cout)
413 419 return
420
421 hist = history_manager.get_history(index, raw, print_outputs)
414 422
415 width = len(str(final))
423 width = len(str(max(hist.iterkeys())))
416 424 line_sep = ['','\n']
417 print_nums = 'n' in opts
418 print_outputs = 'o' in opts
419 pyprompts = 'p' in opts
420 425
421 426 found = False
422 427 if pattern is not None:
423 sh = self.shell.history_manager.shadowhist.all()
428 sh = history_manager.shadow_hist.all()
424 429 for idx, s in sh:
425 430 if fnmatch.fnmatch(s, pattern):
426 431 print("0%d: %s" %(idx, s.expandtabs(4)), file=outfile)
@@ -432,41 +437,39 b" def magic_history(self, parameter_s = ''):"
432 437 file=outfile)
433 438 print("=== start of normal history ===", file=outfile)
434 439
435 for in_num in range(init, final):
440 for in_num, inline in sorted(hist.iteritems()):
436 441 # Print user history with tabs expanded to 4 spaces. The GUI clients
437 442 # use hard tabs for easier usability in auto-indented code, but we want
438 443 # to produce PEP-8 compliant history for safe pasting into an editor.
439 inline = input_hist[in_num].expandtabs(4).rstrip()+'\n'
444 if print_outputs:
445 inline, output = inline
446 inline = inline.expandtabs(4).rstrip()
440 447
441 448 if pattern is not None and not fnmatch.fnmatch(inline, pattern):
442 449 continue
443 450
444 multiline = int(inline.count('\n') > 1)
451 multiline = "\n" in inline
445 452 if print_nums:
446 453 print('%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
447 file=outfile)
454 file=outfile, end='')
448 455 if pyprompts:
449 print('>>>', file=outfile)
456 inline = ">>> " + inline
450 457 if multiline:
451 458 lines = inline.splitlines()
452 459 print('\n... '.join(lines), file=outfile)
453 460 print('... ', file=outfile)
454 461 else:
455 print(inline, end='', file=outfile)
462 print(inline, file=outfile)
456 463 else:
457 print(inline, end='', file=outfile)
458 if print_outputs:
459 output = self.shell.history_manager.output_hist.get(in_num)
460 if output is not None:
461 print(repr(output), file=outfile)
464 print(inline, file=outfile)
465 if print_outputs and output:
466 print(repr(output), file=outfile)
462 467
463 468 if close_at_end:
464 469 outfile.close()
465 470
466
467 def magic_hist(self, parameter_s=''):
468 """Alternate name for %history."""
469 return self.magic_history(parameter_s)
471 # %hist is an alternative name
472 magic_hist = magic_history
470 473
471 474
472 475 def rep_f(self, arg):
@@ -1248,7 +1248,7 b' class InteractiveShell(Configurable, Magic):'
1248 1248
1249 1249 def init_history(self):
1250 1250 """Sets up the command history, and starts regular autosaves."""
1251 self.history_manager = HistoryManager(shell=self)
1251 self.history_manager = HistoryManager(shell=self, load_history=True)
1252 1252
1253 1253 def save_history(self):
1254 1254 """Save input history to a file (via readline library)."""
@@ -1560,11 +1560,8 b' class InteractiveShell(Configurable, Magic):'
1560 1560 readline.set_completer_delims(delims)
1561 1561 # otherwise we end up with a monster history after a while:
1562 1562 readline.set_history_length(self.history_length)
1563 try:
1564 #print '*** Reading readline history' # dbg
1565 self.reload_history()
1566 except IOError:
1567 pass # It doesn't exist yet.
1563
1564 self.history_manager.populate_readline_history()
1568 1565
1569 1566 # Configure auto-indent for all platforms
1570 1567 self.set_autoindent(self.autoindent)
@@ -19,9 +19,9 b' class Macro(IPyAutocall):'
19 19 Args to macro are available in _margv list if you need them.
20 20 """
21 21
22 def __init__(self,data):
22 def __init__(self,code):
23 23 """store the macro value, as a single string which can be executed"""
24 self.value = '\n'.join(data).rstrip()+'\n'
24 self.value = code.rstrip()+'\n'
25 25
26 26 def __str__(self):
27 27 return self.value
@@ -184,11 +184,7 b' python-profiler package from non-free.""")'
184 184 N:M -> standard python form, means including items N...(M-1).
185 185
186 186 N-M -> include items N..M (closed endpoint)."""
187
188 if raw:
189 hist = self.shell.history_manager.input_hist_raw
190 else:
191 hist = self.shell.history_manager.input_hist_parsed
187 history_manager = self.shell.history_manager
192 188
193 189 cmds = []
194 190 for chunk in slices:
@@ -200,7 +196,8 b' python-profiler package from non-free.""")'
200 196 else:
201 197 ini = int(chunk)
202 198 fin = ini+1
203 cmds.append('\n'.join(hist[ini:fin]))
199 hist = history_manager.get_history((ini,fin), raw=raw, output=False)
200 cmds.append('\n'.join(hist[i] for i in sorted(hist.iterkeys())))
204 201 return cmds
205 202
206 203 def arg_err(self,func):
@@ -2044,7 +2041,7 b' Currently the magic system has the following functions:\\n"""'
2044 2041
2045 2042 #print 'rng',ranges # dbg
2046 2043 lines = self.extract_input_slices(ranges,opts.has_key('r'))
2047 macro = Macro(lines)
2044 macro = Macro("\n".join(lines))
2048 2045 self.shell.define_macro(name, macro)
2049 2046 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
2050 2047 print 'Macro contents:'
@@ -2294,7 +2291,7 b' Currently the magic system has the following functions:\\n"""'
2294 2291 # This means that you can't edit files whose names begin with
2295 2292 # numbers this way. Tough.
2296 2293 ranges = args.split()
2297 data = ''.join(self.extract_input_slices(ranges,opts_r))
2294 data = '\n'.join(self.extract_input_slices(ranges,opts_r))
2298 2295 elif args.endswith('.py'):
2299 2296 filename = make_filename(args)
2300 2297 data = ''
General Comments 0
You need to be logged in to leave comments. Login now