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. |
|
|
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= |
|
|
216 | start=offset+1; stop=n | |
|
208 | 217 | elif isinstance(index, int): |
|
209 | 218 | start=n-index; stop=n |
|
210 |
elif |
|
|
211 |
start=index[0] |
|
|
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 |
|
|
|
385 | input_hist = self.shell.history_manager.input_hist_parsed | |
|
386 |
|
|
|
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 |
in |
|
|
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 |
|
|
|
407 | init = max(1, final-int(args[0])) | |
|
413 | index = int(args[0]) | |
|
408 | 414 | elif len(args) == 2: |
|
409 |
in |
|
|
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( |
|
|
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 = |
|
|
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 |
|
|
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 = |
|
|
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, |
|
|
462 | print(inline, file=outfile) | |
|
456 | 463 | else: |
|
457 |
print(inline, |
|
|
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 |
|
|
|
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, |
|
|
22 | def __init__(self,code): | |
|
23 | 23 | """store the macro value, as a single string which can be executed""" |
|
24 |
self.value = |
|
|
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