Show More
@@ -13,13 +13,8 b'' | |||
|
13 | 13 | from __future__ import print_function |
|
14 | 14 | |
|
15 | 15 | # Stdlib imports |
|
16 | import atexit | |
|
17 | import fnmatch | |
|
18 | import json | |
|
19 | 16 | import os |
|
20 |
import s |
|
|
21 | import threading | |
|
22 | import time | |
|
17 | import sqlite3 | |
|
23 | 18 | |
|
24 | 19 | # Our own packages |
|
25 | 20 | import IPython.utils.io |
@@ -50,14 +45,10 b' class HistoryManager(object):' | |||
|
50 | 45 | output_hist = None |
|
51 | 46 | # String with path to the history file |
|
52 | 47 | hist_file = None |
|
53 | # PickleShareDB instance holding the raw data for the shadow history | |
|
54 |
|
|
|
55 | # ShadowHist instance with the actual shadow history | |
|
56 | shadow_hist = None | |
|
57 | ||
|
58 | # Offset so the first line of the current session is #1. Can be | |
|
59 | # updated after loading history from file. | |
|
60 | session_offset = -1 | |
|
48 | # The SQLite database | |
|
49 | db = None | |
|
50 | # The number of the current session in the history database | |
|
51 | session_number = None | |
|
61 | 52 | |
|
62 | 53 | # Private interface |
|
63 | 54 | # Variables used to store the three last inputs from the user. On each new |
@@ -83,12 +74,13 b' class HistoryManager(object):' | |||
|
83 | 74 | # We need a pointer back to the shell for various tasks. |
|
84 | 75 | self.shell = shell |
|
85 | 76 | |
|
86 | # List of input with multi-line handling. | |
|
87 | self.input_hist_parsed = [] | |
|
77 | # List of input with multi-line handling. One blank entry so indexing | |
|
78 | # starts from 1. | |
|
79 | self.input_hist_parsed = [""] | |
|
88 | 80 | # This one will hold the 'raw' input history, without any |
|
89 | 81 | # pre-processing. This will allow users to retrieve the input just as |
|
90 | 82 | # it was exactly typed in by the user, with %hist -r. |
|
91 | self.input_hist_raw = [] | |
|
83 | self.input_hist_raw = [""] | |
|
92 | 84 | |
|
93 | 85 | # list of visited directories |
|
94 | 86 | try: |
@@ -104,99 +96,100 b' class HistoryManager(object):' | |||
|
104 | 96 | histfname = 'history-%s' % shell.profile |
|
105 | 97 | else: |
|
106 | 98 | histfname = 'history' |
|
107 |
self.hist_file = os.path.join(shell.ipython_dir, histfname + '. |
|
|
108 | ||
|
109 | # Objects related to shadow history management | |
|
110 | self._init_shadow_hist() | |
|
99 | self.hist_file = os.path.join(shell.ipython_dir, histfname + '.sqlite') | |
|
111 | 100 | |
|
112 | 101 | self._i00, self._i, self._ii, self._iii = '','','','' |
|
113 | 102 | |
|
114 | 103 | self._exit_commands = set(['Quit', 'quit', 'Exit', 'exit', '%Quit', |
|
115 | 104 | '%quit', '%Exit', '%exit']) |
|
116 | 105 | |
|
117 | # Object is fully initialized, we can now call methods on it. | |
|
106 | self.init_db() | |
|
118 | 107 | |
|
119 | if load_history: | |
|
120 | self.reload_history() | |
|
121 | self.session_offset = len(self.input_hist_raw) -1 | |
|
108 | def init_db(self): | |
|
109 | self.db = sqlite3.connect(self.hist_file) | |
|
110 | self.db.execute("""CREATE TABLE IF NOT EXISTS history (session integer, | |
|
111 | line integer, source text, source_raw text, | |
|
112 | PRIMARY KEY (session, line))""") | |
|
113 | cur = self.db.execute("""SELECT name FROM sqlite_master WHERE | |
|
114 | type='table' AND name='singletons'""") | |
|
115 | if not cur.fetchone(): | |
|
116 | self.db.execute("""CREATE TABLE singletons | |
|
117 | (name text PRIMARY KEY, value)""") | |
|
118 | self.db.execute("""INSERT INTO singletons VALUES | |
|
119 | ('session_number', 1)""") | |
|
120 | self.db.commit() | |
|
121 | cur = self.db.execute("""SELECT value FROM singletons WHERE | |
|
122 | name='session_number'""") | |
|
123 | self.session_number = cur.fetchone()[0] | |
|
122 | 124 | |
|
123 | # Create and start the autosaver. | |
|
124 | self.autosave_flag = threading.Event() | |
|
125 | self.autosave_timer = HistorySaveThread(self.autosave_flag, 60) | |
|
126 |
self. |
|
|
127 | # Register the autosave handler to be triggered as a post execute | |
|
128 | # callback. | |
|
129 | self.shell.register_post_execute(self.autosave_if_due) | |
|
125 | #Increment by one for next session. | |
|
126 | self.db.execute("""UPDATE singletons SET value=? WHERE | |
|
127 | name='session_number'""", (self.session_number+1,)) | |
|
128 | self.db.commit() | |
|
129 | ||
|
130 | def get_db_history(self, session, start=1, stop=None, raw=True): | |
|
131 | """Retrieve input history from the database by session. | |
|
130 | 132 |
|
|
131 | ||
|
132 | def _init_shadow_hist(self): | |
|
133 | try: | |
|
134 | self.shadow_db = PickleShareDB(os.path.join( | |
|
135 | self.shell.ipython_dir, 'db')) | |
|
136 | except UnicodeDecodeError: | |
|
137 | print("Your ipython_dir can't be decoded to unicode!") | |
|
138 | print("Please set HOME environment variable to something that") | |
|
139 | print(r"only has ASCII characters, e.g. c:\home") | |
|
140 | print("Now it is", self.ipython_dir) | |
|
141 | sys.exit() | |
|
142 | self.shadow_hist = ShadowHist(self.shadow_db, self.shell) | |
|
133 | Parameters | |
|
134 | ---------- | |
|
135 | session : int | |
|
136 | Session number to retrieve. If negative, counts back from current | |
|
137 | session (so -1 is previous session). | |
|
138 | start : int | |
|
139 | First line to retrieve. | |
|
140 | stop : int | |
|
141 | Last line to retrieve. If None, retrieve to the end of the session. | |
|
142 | raw : bool | |
|
143 | If True, return raw input | |
|
144 | ||
|
145 | Returns | |
|
146 | ------- | |
|
147 | An iterator over the desired lines. | |
|
148 | """ | |
|
149 | toget = 'source_raw' if raw else 'source' | |
|
150 | if session < 0: | |
|
151 | session += self.session_number | |
|
143 | 152 | |
|
144 | def populate_readline_history(self): | |
|
145 | """Populate the readline history from the raw history. | |
|
146 | ||
|
147 | We only store one copy of the raw history, which is persisted to a json | |
|
148 | file on disk. The readline history is repopulated from the contents of | |
|
149 | this file.""" | |
|
150 | ||
|
151 | try: | |
|
152 | self.shell.readline.clear_history() | |
|
153 | except AttributeError: | |
|
154 | pass | |
|
153 | if stop: | |
|
154 | cur = self.db.execute("SELECT " + toget + """ FROM history WHERE | |
|
155 | session==? AND line BETWEEN ? and ?""", | |
|
156 | (session, start, stop)) | |
|
155 | 157 | else: |
|
156 | for h in self.input_hist_raw: | |
|
157 | if not h.isspace(): | |
|
158 | for line in h.splitlines(): | |
|
159 | self.shell.readline.add_history(line) | |
|
160 | ||
|
161 | def save_history(self): | |
|
162 | """Save input history to a file (via readline library).""" | |
|
163 | hist = dict(raw=self.input_hist_raw, #[-self.shell.history_length:], | |
|
164 | parsed=self.input_hist_parsed) #[-self.shell.history_length:]) | |
|
165 | with open(self.hist_file,'wt') as hfile: | |
|
166 | json.dump(hist, hfile, | |
|
167 | sort_keys=True, indent=4) | |
|
168 | ||
|
169 | def autosave_if_due(self): | |
|
170 | """Check if the autosave event is set; if so, save history. We do it | |
|
171 | this way so that the save takes place in the main thread.""" | |
|
172 | if self.autosave_flag.is_set(): | |
|
173 | self.save_history() | |
|
174 | self.autosave_flag.clear() | |
|
158 | cur = self.db.execute("SELECT " + toget + """ FROM history WHERE | |
|
159 | session==? AND line>=?""", (session, start)) | |
|
160 | return (x[0] for x in cur) | |
|
161 | ||
|
162 | def tail_db_history(self, n=10, raw=True): | |
|
163 | """Get the last n lines from the history database.""" | |
|
164 | toget = 'source_raw' if raw else 'source' | |
|
165 | cur = self.db.execute("SELECT " + toget + """ FROM history ORDER BY | |
|
166 | session DESC, line DESC LIMIT ?""", (n,)) | |
|
167 | return (x[0] for x in reversed(cur.fetchall())) | |
|
175 | 168 | |
|
176 | def reload_history(self): | |
|
177 | """Reload the input history from disk file.""" | |
|
178 | ||
|
179 | with open(self.hist_file,'rt') as hfile: | |
|
180 |
|
|
|
181 | hist = json.load(hfile) | |
|
182 | except ValueError: # Ignore it if JSON is corrupt. | |
|
183 | return | |
|
184 | self.input_hist_parsed = hist['parsed'] | |
|
185 | self.input_hist_raw = hist['raw'] | |
|
186 | if self.shell.has_readline: | |
|
187 | self.populate_readline_history() | |
|
169 | def globsearch_db(self, pattern="*"): | |
|
170 | """Search the database using unix glob-style matching (wildcards * and | |
|
171 | ?, escape using \). | |
|
172 | ||
|
173 | Returns | |
|
174 | ------- | |
|
175 | An iterator over tuples: (session, line_number, command) | |
|
176 | """ | |
|
177 | return self.db.execute("""SELECT session, line, source_raw FROM history | |
|
178 | WHERE source_raw GLOB ?""", (pattern,)) | |
|
188 | 179 | |
|
189 |
def get_history(self, |
|
|
180 | def get_history(self, start=1, stop=None, raw=False, output=True): | |
|
190 | 181 | """Get the history list. |
|
191 | 182 | |
|
192 | 183 | Get the input and output history. |
|
193 | 184 | |
|
194 | 185 | Parameters |
|
195 | 186 | ---------- |
|
196 | index : n or (n1, n2) or None | |
|
197 | If n, then the last n entries. If a tuple, then all in | |
|
198 | range(n1, n2). If None, then all entries. Raises IndexError if | |
|
199 | the format of index is incorrect. | |
|
187 | start : int | |
|
188 | From (prompt number in the current session). Negative numbers count | |
|
189 | back from the end. | |
|
190 | stop : int | |
|
191 | To (prompt number in the current session, exclusive). Negative | |
|
192 | numbers count back from the end, and None goes to the end. | |
|
200 | 193 | raw : bool |
|
201 | 194 | If True, return the raw input. |
|
202 | 195 | output : bool |
@@ -217,29 +210,21 b' class HistoryManager(object):' | |||
|
217 | 210 | input_hist = self.input_hist_parsed |
|
218 | 211 | if output: |
|
219 | 212 | output_hist = self.output_hist |
|
220 | ||
|
221 | if this_session: | |
|
222 | offset = self.session_offset | |
|
223 | else: | |
|
224 | offset = -1 | |
|
225 | 213 | |
|
226 | 214 | n = len(input_hist) |
|
227 |
if |
|
|
228 |
start= |
|
|
229 | elif isinstance(index, int): | |
|
230 |
st |
|
|
231 |
elif |
|
|
232 |
st |
|
|
233 | stop = index[1] + offset | |
|
234 | else: | |
|
235 | raise IndexError('Not a valid index for the input history: %r' | |
|
236 | % index) | |
|
215 | if start < 0: | |
|
216 | start += n | |
|
217 | if not stop: | |
|
218 | stop = n | |
|
219 | elif stop < 0: | |
|
220 | stop += n | |
|
221 | ||
|
237 | 222 | hist = {} |
|
238 | 223 | for i in range(start, stop): |
|
239 | 224 | if output: |
|
240 |
hist[i |
|
|
225 | hist[i] = (input_hist[i], output_hist.get(i)) | |
|
241 | 226 | else: |
|
242 |
hist[i |
|
|
227 | hist[i] = input_hist[i] | |
|
243 | 228 | return hist |
|
244 | 229 | |
|
245 | 230 | def store_inputs(self, source, source_raw=None): |
@@ -264,7 +249,10 b' class HistoryManager(object):' | |||
|
264 | 249 | |
|
265 | 250 | self.input_hist_parsed.append(source.rstrip()) |
|
266 | 251 | self.input_hist_raw.append(source_raw.rstrip()) |
|
267 | self.shadow_hist.add(source) | |
|
252 | with self.db: | |
|
253 | self.db.execute("INSERT INTO history VALUES (?, ?, ?, ?)", | |
|
254 | (self.session_number, self.shell.execution_count, | |
|
255 | source, source_raw)) | |
|
268 | 256 | |
|
269 | 257 | # update the auto _i variables |
|
270 | 258 | self._iii = self._ii |
@@ -282,8 +270,12 b' class HistoryManager(object):' | |||
|
282 | 270 | |
|
283 | 271 | def sync_inputs(self): |
|
284 | 272 | """Ensure raw and translated histories have same length.""" |
|
285 |
|
|
|
286 |
|
|
|
273 | lr = len(self.input_hist_raw) | |
|
274 | lp = len(self.input_hist_parsed) | |
|
275 | if lp < lr: | |
|
276 | self.input_hist_raw[:lr-lp] = [] | |
|
277 | elif lr < lp: | |
|
278 | self.input_hist_parsed[:lp-lr] = [] | |
|
287 | 279 | |
|
288 | 280 | def reset(self): |
|
289 | 281 | """Clear all histories managed by this object.""" |
@@ -292,41 +284,6 b' class HistoryManager(object):' | |||
|
292 | 284 | self.output_hist.clear() |
|
293 | 285 | # The directory history can't be completely empty |
|
294 | 286 | self.dir_hist[:] = [os.getcwd()] |
|
295 | # Reset session offset to -1, so next command counts as #1 | |
|
296 | self.session_offset = -1 | |
|
297 | ||
|
298 | class HistorySaveThread(threading.Thread): | |
|
299 | """This thread makes IPython save history periodically. | |
|
300 | ||
|
301 | Without this class, IPython would only save the history on a clean exit. | |
|
302 | This saves the history periodically (the current default is once per | |
|
303 | minute), so that it is not lost in the event of a crash. | |
|
304 | ||
|
305 | The implementation sets an event to indicate that history should be saved. | |
|
306 | The actual save is carried out after executing a user command, to avoid | |
|
307 | thread issues. | |
|
308 | """ | |
|
309 | daemon = True | |
|
310 | ||
|
311 | def __init__(self, autosave_flag, time_interval=60): | |
|
312 | threading.Thread.__init__(self) | |
|
313 | self.time_interval = time_interval | |
|
314 | self.autosave_flag = autosave_flag | |
|
315 | self.exit_now = threading.Event() | |
|
316 | # Ensure the thread is stopped tidily when exiting normally | |
|
317 | atexit.register(self.stop) | |
|
318 | ||
|
319 | def run(self): | |
|
320 | while True: | |
|
321 | self.exit_now.wait(self.time_interval) | |
|
322 | if self.exit_now.is_set(): | |
|
323 | break | |
|
324 | self.autosave_flag.set() | |
|
325 | ||
|
326 | def stop(self): | |
|
327 | """Safely and quickly stop the autosave timer thread.""" | |
|
328 | self.exit_now.set() | |
|
329 | self.join() | |
|
330 | 287 | |
|
331 | 288 | @testdec.skip_doctest |
|
332 | 289 | def magic_history(self, parameter_s = ''): |
@@ -364,9 +321,8 b" def magic_history(self, parameter_s = ''):" | |||
|
364 | 321 | 'get_ipython().magic("%cd /")' instead of '%cd /'. |
|
365 | 322 | |
|
366 | 323 | -g: treat the arg as a pattern to grep for in (full) history. |
|
367 |
This includes the |
|
|
368 |
Use '%hist -g' to show full s |
|
|
369 | In shadow history, every index nuwber starts with 0. | |
|
324 | This includes the saved history (almost all commands ever written). | |
|
325 | Use '%hist -g' to show full saved history (may be very long). | |
|
370 | 326 | |
|
371 | 327 | -f FILENAME: instead of printing the output to the screen, redirect it to |
|
372 | 328 | the given file. The file is always overwritten, though IPython asks for |
@@ -415,39 +371,37 b" def magic_history(self, parameter_s = ''):" | |||
|
415 | 371 | default_length = 40 |
|
416 | 372 | pattern = None |
|
417 | 373 | if 'g' in opts: |
|
418 |
|
|
|
374 | start = 1; stop = None | |
|
419 | 375 | parts = parameter_s.split(None, 1) |
|
420 | 376 | if len(parts) == 1: |
|
421 | 377 | parts += '*' |
|
422 | 378 | head, pattern = parts |
|
423 | 379 | pattern = "*" + pattern + "*" |
|
424 | 380 | elif len(args) == 0: |
|
425 |
|
|
|
381 | start = 1; stop = None | |
|
426 | 382 | elif len(args) == 1: |
|
427 |
|
|
|
383 | start = -int(args[0]); stop=None | |
|
428 | 384 | elif len(args) == 2: |
|
429 | index = map(int, args) | |
|
385 | start = int(args[0]); stop = int(args[1]) | |
|
430 | 386 | else: |
|
431 | 387 | warn('%hist takes 0, 1 or 2 arguments separated by spaces.') |
|
432 | 388 | print(self.magic_hist.__doc__, file=IPython.utils.io.Term.cout) |
|
433 | 389 | return |
|
434 | 390 | |
|
435 |
hist = history_manager.get_history( |
|
|
391 | hist = history_manager.get_history(start, stop, raw, print_outputs) | |
|
436 | 392 | |
|
437 | 393 | width = len(str(max(hist.iterkeys()))) |
|
438 | 394 | line_sep = ['','\n'] |
|
439 | 395 | |
|
440 | 396 | found = False |
|
441 | 397 | if pattern is not None: |
|
442 | sh = history_manager.shadow_hist.all() | |
|
443 | for idx, s in sh: | |
|
444 | if fnmatch.fnmatch(s, pattern): | |
|
445 | print("0%d: %s" %(idx, s.expandtabs(4)), file=outfile) | |
|
446 | found = True | |
|
398 | for session, line, s in history_manager.globsearch_db(pattern): | |
|
399 | print("%d#%d: %s" %(session, line, s.expandtabs(4)), file=outfile) | |
|
400 | found = True | |
|
447 | 401 | |
|
448 | 402 | if found: |
|
449 | 403 | print("===", file=outfile) |
|
450 |
print("shadow history ends, fetch by %rep |
|
|
404 | print("shadow history ends, fetch by %rep session#line", | |
|
451 | 405 | file=outfile) |
|
452 | 406 | print("=== start of normal history ===", file=outfile) |
|
453 | 407 | |
@@ -545,50 +499,6 b' def rep_f(self, arg):' | |||
|
545 | 499 | self.run_cell(lines) |
|
546 | 500 | except ValueError: |
|
547 | 501 | print("Not found in recent history:", args) |
|
548 | ||
|
549 | ||
|
550 | _sentinel = object() | |
|
551 | ||
|
552 | class ShadowHist(object): | |
|
553 | def __init__(self, db, shell): | |
|
554 | # cmd => idx mapping | |
|
555 | self.curidx = 0 | |
|
556 | self.db = db | |
|
557 | self.disabled = False | |
|
558 | self.shell = shell | |
|
559 | ||
|
560 | def inc_idx(self): | |
|
561 | idx = self.db.get('shadowhist_idx', 1) | |
|
562 | self.db['shadowhist_idx'] = idx + 1 | |
|
563 | return idx | |
|
564 | ||
|
565 | def add(self, ent): | |
|
566 | if self.disabled: | |
|
567 | return | |
|
568 | try: | |
|
569 | old = self.db.hget('shadowhist', ent, _sentinel) | |
|
570 | if old is not _sentinel: | |
|
571 | return | |
|
572 | newidx = self.inc_idx() | |
|
573 | #print("new", newidx) # dbg | |
|
574 | self.db.hset('shadowhist',ent, newidx) | |
|
575 | except: | |
|
576 | self.shell.showtraceback() | |
|
577 | print("WARNING: disabling shadow history") | |
|
578 | self.disabled = True | |
|
579 | ||
|
580 | def all(self): | |
|
581 | d = self.db.hdict('shadowhist') | |
|
582 | items = [(i,s) for (s,i) in d.iteritems()] | |
|
583 | items.sort() | |
|
584 | return items | |
|
585 | ||
|
586 | def get(self, idx): | |
|
587 | all = self.all() | |
|
588 | ||
|
589 | for k, v in all: | |
|
590 | if k == idx: | |
|
591 | return v | |
|
592 | 502 | |
|
593 | 503 | |
|
594 | 504 | def init_ipython(ip): |
@@ -56,11 +56,11 b' from IPython.core.prefilter import PrefilterManager, ESC_MAGIC' | |||
|
56 | 56 | from IPython.external.Itpl import ItplNS |
|
57 | 57 | from IPython.utils import PyColorize |
|
58 | 58 | from IPython.utils import io |
|
59 | from IPython.utils import pickleshare | |
|
60 | 59 | from IPython.utils.doctestreload import doctest_reload |
|
61 | 60 | from IPython.utils.io import ask_yes_no, rprint |
|
62 | 61 | from IPython.utils.ipstruct import Struct |
|
63 | 62 | from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError |
|
63 | from IPython.utils.pickleshare import PickleShareDB | |
|
64 | 64 | from IPython.utils.process import system, getoutput |
|
65 | 65 | from IPython.utils.strdispatch import StrDispatch |
|
66 | 66 | from IPython.utils.syspathcontext import prepended_to_syspath |
@@ -250,6 +250,11 b' class InteractiveShell(Configurable, Magic):' | |||
|
250 | 250 | # is what we want to do. |
|
251 | 251 | self.save_sys_module_state() |
|
252 | 252 | self.init_sys_modules() |
|
253 | ||
|
254 | # While we're trying to have each part of the code directly access what | |
|
255 | # it needs without keeping redundant references to objects, we have too | |
|
256 | # much legacy code that expects ip.db to exist. | |
|
257 | self.db = PickleShareDB(os.path.join(self.ipython_dir, 'db')) | |
|
253 | 258 | |
|
254 | 259 | self.init_history() |
|
255 | 260 | self.init_encoding() |
@@ -300,14 +305,6 b' class InteractiveShell(Configurable, Magic):' | |||
|
300 | 305 | self.hooks.late_startup_hook() |
|
301 | 306 | atexit.register(self.atexit_operations) |
|
302 | 307 | |
|
303 | # While we're trying to have each part of the code directly access what it | |
|
304 | # needs without keeping redundant references to objects, we have too much | |
|
305 | # legacy code that expects ip.db to exist, so let's make it a property that | |
|
306 | # retrieves the underlying object from our new history manager. | |
|
307 | @property | |
|
308 | def db(self): | |
|
309 | return self.history_manager.shadow_db | |
|
310 | ||
|
311 | 308 | @classmethod |
|
312 | 309 | def instance(cls, *args, **kwargs): |
|
313 | 310 | """Returns a global InteractiveShell instance.""" |
@@ -1248,15 +1245,7 b' class InteractiveShell(Configurable, Magic):' | |||
|
1248 | 1245 | |
|
1249 | 1246 | def init_history(self): |
|
1250 | 1247 | """Sets up the command history, and starts regular autosaves.""" |
|
1251 |
self.history_manager = HistoryManager(shell=self |
|
|
1252 | ||
|
1253 | def save_history(self): | |
|
1254 | """Save input history to a file (via readline library).""" | |
|
1255 | self.history_manager.save_history() | |
|
1256 | ||
|
1257 | def reload_history(self): | |
|
1258 | """Reload the input history from disk file.""" | |
|
1259 | self.history_manager.reload_history() | |
|
1248 | self.history_manager = HistoryManager(shell=self) | |
|
1260 | 1249 | |
|
1261 | 1250 | def history_saving_wrapper(self, func): |
|
1262 | 1251 | """ Wrap func for readline history saving |
@@ -1277,8 +1266,8 b' class InteractiveShell(Configurable, Magic):' | |||
|
1277 | 1266 | self.reload_history() |
|
1278 | 1267 | return wrapper |
|
1279 | 1268 | |
|
1280 |
def get_history(self, |
|
|
1281 |
return self.history_manager.get_history( |
|
|
1269 | def get_history(self, start=1, stop=None, raw=False, output=True): | |
|
1270 | return self.history_manager.get_history(start, stop, raw, output) | |
|
1282 | 1271 | |
|
1283 | 1272 | |
|
1284 | 1273 | #------------------------------------------------------------------------- |
@@ -1561,7 +1550,11 b' class InteractiveShell(Configurable, Magic):' | |||
|
1561 | 1550 | # otherwise we end up with a monster history after a while: |
|
1562 | 1551 | readline.set_history_length(self.history_length) |
|
1563 | 1552 | |
|
1564 | self.history_manager.populate_readline_history() | |
|
1553 | # Load the last 1000 lines from history | |
|
1554 | for cell in self.history_manager.tail_db_history(1000): | |
|
1555 | if cell.strip(): # Ignore blank lines | |
|
1556 | for line in cell.splitlines(): | |
|
1557 | readline.add_history(line) | |
|
1565 | 1558 | |
|
1566 | 1559 | # Configure auto-indent for all platforms |
|
1567 | 1560 | self.set_autoindent(self.autoindent) |
@@ -2536,8 +2529,6 b' class InteractiveShell(Configurable, Magic):' | |||
|
2536 | 2529 | except OSError: |
|
2537 | 2530 | pass |
|
2538 | 2531 | |
|
2539 | self.save_history() | |
|
2540 | ||
|
2541 | 2532 | # Clear all user namespaces to release all references cleanly. |
|
2542 | 2533 | self.reset() |
|
2543 | 2534 |
General Comments 0
You need to be logged in to leave comments.
Login now