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