##// END OF EJS Templates
Prefer %recall over %rep in docstring.
Thomas Kluyver -
Show More
@@ -1,800 +1,801 b''
1 1 """ History related magics and functionality """
2 2 #-----------------------------------------------------------------------------
3 3 # Copyright (C) 2010 The IPython Development Team.
4 4 #
5 5 # Distributed under the terms of the BSD License.
6 6 #
7 7 # The full license is in the file COPYING.txt, distributed with this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13 from __future__ import print_function
14 14
15 15 # Stdlib imports
16 16 import atexit
17 17 import datetime
18 18 import os
19 19 import re
20 20 import sqlite3
21 21 import threading
22 22
23 23 # Our own packages
24 24 from IPython.config.configurable import Configurable
25 25
26 26 from IPython.testing.skipdoctest import skip_doctest
27 27 from IPython.utils import io
28 28 from IPython.utils.traitlets import Bool, Dict, Instance, Int, List, Unicode
29 29 from IPython.utils.warn import warn
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Classes and functions
33 33 #-----------------------------------------------------------------------------
34 34
35 35 class HistoryManager(Configurable):
36 36 """A class to organize all history-related functionality in one place.
37 37 """
38 38 # Public interface
39 39
40 40 # An instance of the IPython shell we are attached to
41 41 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
42 42 # Lists to hold processed and raw history. These start with a blank entry
43 43 # so that we can index them starting from 1
44 44 input_hist_parsed = List([""])
45 45 input_hist_raw = List([""])
46 46 # A list of directories visited during session
47 47 dir_hist = List()
48 48 def _dir_hist_default(self):
49 49 try:
50 50 return [os.getcwdu()]
51 51 except OSError:
52 52 return []
53 53
54 54 # A dict of output history, keyed with ints from the shell's
55 55 # execution count.
56 56 output_hist = Dict()
57 57 # The text/plain repr of outputs.
58 58 output_hist_reprs = Dict()
59 59
60 60 # String holding the path to the history file
61 61 hist_file = Unicode(config=True)
62 62
63 63 # The SQLite database
64 64 db = Instance(sqlite3.Connection)
65 65 # The number of the current session in the history database
66 66 session_number = Int()
67 67 # Should we log output to the database? (default no)
68 68 db_log_output = Bool(False, config=True)
69 69 # Write to database every x commands (higher values save disk access & power)
70 70 # Values of 1 or less effectively disable caching.
71 71 db_cache_size = Int(0, config=True)
72 72 # The input and output caches
73 73 db_input_cache = List()
74 74 db_output_cache = List()
75 75
76 76 # History saving in separate thread
77 77 save_thread = Instance('IPython.core.history.HistorySavingThread')
78 78 # N.B. Event is a function returning an instance of _Event.
79 79 save_flag = Instance(threading._Event)
80 80
81 81 # Private interface
82 82 # Variables used to store the three last inputs from the user. On each new
83 83 # history update, we populate the user's namespace with these, shifted as
84 84 # necessary.
85 85 _i00 = Unicode(u'')
86 86 _i = Unicode(u'')
87 87 _ii = Unicode(u'')
88 88 _iii = Unicode(u'')
89 89
90 90 # A regex matching all forms of the exit command, so that we don't store
91 91 # them in the history (it's annoying to rewind the first entry and land on
92 92 # an exit call).
93 93 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
94 94
95 95 def __init__(self, shell, config=None, **traits):
96 96 """Create a new history manager associated with a shell instance.
97 97 """
98 98 # We need a pointer back to the shell for various tasks.
99 99 super(HistoryManager, self).__init__(shell=shell, config=config,
100 100 **traits)
101 101
102 102 if self.hist_file == u'':
103 103 # No one has set the hist_file, yet.
104 104 histfname = 'history'
105 105 self.hist_file = os.path.join(shell.profile_dir.location, histfname + '.sqlite')
106 106
107 107 try:
108 108 self.init_db()
109 109 except sqlite3.DatabaseError:
110 110 if os.path.isfile(self.hist_file):
111 111 # Try to move the file out of the way.
112 112 newpath = os.path.join(self.shell.profile_dir.location, "hist-corrupt.sqlite")
113 113 os.rename(self.hist_file, newpath)
114 114 print("ERROR! History file wasn't a valid SQLite database.",
115 115 "It was moved to %s" % newpath, "and a new file created.")
116 116 self.init_db()
117 117 else:
118 118 # The hist_file is probably :memory: or something else.
119 119 raise
120 120
121 121 self.save_flag = threading.Event()
122 122 self.db_input_cache_lock = threading.Lock()
123 123 self.db_output_cache_lock = threading.Lock()
124 124 self.save_thread = HistorySavingThread(self)
125 125 self.save_thread.start()
126 126
127 127 self.new_session()
128 128
129 129
130 130 def init_db(self):
131 131 """Connect to the database, and create tables if necessary."""
132 132 self.db = sqlite3.connect(self.hist_file)
133 133 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
134 134 primary key autoincrement, start timestamp,
135 135 end timestamp, num_cmds integer, remark text)""")
136 136 self.db.execute("""CREATE TABLE IF NOT EXISTS history
137 137 (session integer, line integer, source text, source_raw text,
138 138 PRIMARY KEY (session, line))""")
139 139 # Output history is optional, but ensure the table's there so it can be
140 140 # enabled later.
141 141 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
142 142 (session integer, line integer, output text,
143 143 PRIMARY KEY (session, line))""")
144 144 self.db.commit()
145 145
146 146 def new_session(self, conn=None):
147 147 """Get a new session number."""
148 148 if conn is None:
149 149 conn = self.db
150 150
151 151 with conn:
152 152 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
153 153 NULL, "") """, (datetime.datetime.now(),))
154 154 self.session_number = cur.lastrowid
155 155
156 156 def end_session(self):
157 157 """Close the database session, filling in the end time and line count."""
158 158 self.writeout_cache()
159 159 with self.db:
160 160 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
161 161 session==?""", (datetime.datetime.now(),
162 162 len(self.input_hist_parsed)-1, self.session_number))
163 163 self.session_number = 0
164 164
165 165 def name_session(self, name):
166 166 """Give the current session a name in the history database."""
167 167 with self.db:
168 168 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
169 169 (name, self.session_number))
170 170
171 171 def reset(self, new_session=True):
172 172 """Clear the session history, releasing all object references, and
173 173 optionally open a new session."""
174 174 self.output_hist.clear()
175 175 # The directory history can't be completely empty
176 176 self.dir_hist[:] = [os.getcwdu()]
177 177
178 178 if new_session:
179 179 if self.session_number:
180 180 self.end_session()
181 181 self.input_hist_parsed[:] = [""]
182 182 self.input_hist_raw[:] = [""]
183 183 self.new_session()
184 184
185 185 ## -------------------------------
186 186 ## Methods for retrieving history:
187 187 ## -------------------------------
188 188 def _run_sql(self, sql, params, raw=True, output=False):
189 189 """Prepares and runs an SQL query for the history database.
190 190
191 191 Parameters
192 192 ----------
193 193 sql : str
194 194 Any filtering expressions to go after SELECT ... FROM ...
195 195 params : tuple
196 196 Parameters passed to the SQL query (to replace "?")
197 197 raw, output : bool
198 198 See :meth:`get_range`
199 199
200 200 Returns
201 201 -------
202 202 Tuples as :meth:`get_range`
203 203 """
204 204 toget = 'source_raw' if raw else 'source'
205 205 sqlfrom = "history"
206 206 if output:
207 207 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
208 208 toget = "history.%s, output_history.output" % toget
209 209 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
210 210 (toget, sqlfrom) + sql, params)
211 211 if output: # Regroup into 3-tuples, and parse JSON
212 212 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
213 213 return cur
214 214
215 215
216 216 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
217 217 """Get the last n lines from the history database.
218 218
219 219 Parameters
220 220 ----------
221 221 n : int
222 222 The number of lines to get
223 223 raw, output : bool
224 224 See :meth:`get_range`
225 225 include_latest : bool
226 226 If False (default), n+1 lines are fetched, and the latest one
227 227 is discarded. This is intended to be used where the function
228 228 is called by a user command, which it should not return.
229 229
230 230 Returns
231 231 -------
232 232 Tuples as :meth:`get_range`
233 233 """
234 234 self.writeout_cache()
235 235 if not include_latest:
236 236 n += 1
237 237 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
238 238 (n,), raw=raw, output=output)
239 239 if not include_latest:
240 240 return reversed(list(cur)[1:])
241 241 return reversed(list(cur))
242 242
243 243 def search(self, pattern="*", raw=True, search_raw=True,
244 244 output=False):
245 245 """Search the database using unix glob-style matching (wildcards
246 246 * and ?).
247 247
248 248 Parameters
249 249 ----------
250 250 pattern : str
251 251 The wildcarded pattern to match when searching
252 252 search_raw : bool
253 253 If True, search the raw input, otherwise, the parsed input
254 254 raw, output : bool
255 255 See :meth:`get_range`
256 256
257 257 Returns
258 258 -------
259 259 Tuples as :meth:`get_range`
260 260 """
261 261 tosearch = "source_raw" if search_raw else "source"
262 262 if output:
263 263 tosearch = "history." + tosearch
264 264 self.writeout_cache()
265 265 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
266 266 raw=raw, output=output)
267 267
268 268 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
269 269 """Get input and output history from the current session. Called by
270 270 get_range, and takes similar parameters."""
271 271 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
272 272
273 273 n = len(input_hist)
274 274 if start < 0:
275 275 start += n
276 276 if not stop:
277 277 stop = n
278 278 elif stop < 0:
279 279 stop += n
280 280
281 281 for i in range(start, stop):
282 282 if output:
283 283 line = (input_hist[i], self.output_hist_reprs.get(i))
284 284 else:
285 285 line = input_hist[i]
286 286 yield (0, i, line)
287 287
288 288 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
289 289 """Retrieve input by session.
290 290
291 291 Parameters
292 292 ----------
293 293 session : int
294 294 Session number to retrieve. The current session is 0, and negative
295 295 numbers count back from current session, so -1 is previous session.
296 296 start : int
297 297 First line to retrieve.
298 298 stop : int
299 299 End of line range (excluded from output itself). If None, retrieve
300 300 to the end of the session.
301 301 raw : bool
302 302 If True, return untranslated input
303 303 output : bool
304 304 If True, attempt to include output. This will be 'real' Python
305 305 objects for the current session, or text reprs from previous
306 306 sessions if db_log_output was enabled at the time. Where no output
307 307 is found, None is used.
308 308
309 309 Returns
310 310 -------
311 311 An iterator over the desired lines. Each line is a 3-tuple, either
312 312 (session, line, input) if output is False, or
313 313 (session, line, (input, output)) if output is True.
314 314 """
315 315 if session == 0 or session==self.session_number: # Current session
316 316 return self._get_range_session(start, stop, raw, output)
317 317 if session < 0:
318 318 session += self.session_number
319 319
320 320 if stop:
321 321 lineclause = "line >= ? AND line < ?"
322 322 params = (session, start, stop)
323 323 else:
324 324 lineclause = "line>=?"
325 325 params = (session, start)
326 326
327 327 return self._run_sql("WHERE session==? AND %s""" % lineclause,
328 328 params, raw=raw, output=output)
329 329
330 330 def get_range_by_str(self, rangestr, raw=True, output=False):
331 331 """Get lines of history from a string of ranges, as used by magic
332 332 commands %hist, %save, %macro, etc.
333 333
334 334 Parameters
335 335 ----------
336 336 rangestr : str
337 337 A string specifying ranges, e.g. "5 ~2/1-4". See
338 338 :func:`magic_history` for full details.
339 339 raw, output : bool
340 340 As :meth:`get_range`
341 341
342 342 Returns
343 343 -------
344 344 Tuples as :meth:`get_range`
345 345 """
346 346 for sess, s, e in extract_hist_ranges(rangestr):
347 347 for line in self.get_range(sess, s, e, raw=raw, output=output):
348 348 yield line
349 349
350 350 ## ----------------------------
351 351 ## Methods for storing history:
352 352 ## ----------------------------
353 353 def store_inputs(self, line_num, source, source_raw=None):
354 354 """Store source and raw input in history and create input cache
355 355 variables _i*.
356 356
357 357 Parameters
358 358 ----------
359 359 line_num : int
360 360 The prompt number of this input.
361 361
362 362 source : str
363 363 Python input.
364 364
365 365 source_raw : str, optional
366 366 If given, this is the raw input without any IPython transformations
367 367 applied to it. If not given, ``source`` is used.
368 368 """
369 369 if source_raw is None:
370 370 source_raw = source
371 371 source = source.rstrip('\n')
372 372 source_raw = source_raw.rstrip('\n')
373 373
374 374 # do not store exit/quit commands
375 375 if self._exit_re.match(source_raw.strip()):
376 376 return
377 377
378 378 self.input_hist_parsed.append(source)
379 379 self.input_hist_raw.append(source_raw)
380 380
381 381 with self.db_input_cache_lock:
382 382 self.db_input_cache.append((line_num, source, source_raw))
383 383 # Trigger to flush cache and write to DB.
384 384 if len(self.db_input_cache) >= self.db_cache_size:
385 385 self.save_flag.set()
386 386
387 387 # update the auto _i variables
388 388 self._iii = self._ii
389 389 self._ii = self._i
390 390 self._i = self._i00
391 391 self._i00 = source_raw
392 392
393 393 # hackish access to user namespace to create _i1,_i2... dynamically
394 394 new_i = '_i%s' % line_num
395 395 to_main = {'_i': self._i,
396 396 '_ii': self._ii,
397 397 '_iii': self._iii,
398 398 new_i : self._i00 }
399 399 self.shell.user_ns.update(to_main)
400 400
401 401 def store_output(self, line_num):
402 402 """If database output logging is enabled, this saves all the
403 403 outputs from the indicated prompt number to the database. It's
404 404 called by run_cell after code has been executed.
405 405
406 406 Parameters
407 407 ----------
408 408 line_num : int
409 409 The line number from which to save outputs
410 410 """
411 411 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
412 412 return
413 413 output = self.output_hist_reprs[line_num]
414 414
415 415 with self.db_output_cache_lock:
416 416 self.db_output_cache.append((line_num, output))
417 417 if self.db_cache_size <= 1:
418 418 self.save_flag.set()
419 419
420 420 def _writeout_input_cache(self, conn):
421 421 with conn:
422 422 for line in self.db_input_cache:
423 423 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
424 424 (self.session_number,)+line)
425 425
426 426 def _writeout_output_cache(self, conn):
427 427 with conn:
428 428 for line in self.db_output_cache:
429 429 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
430 430 (self.session_number,)+line)
431 431
432 432 def writeout_cache(self, conn=None):
433 433 """Write any entries in the cache to the database."""
434 434 if conn is None:
435 435 conn = self.db
436 436
437 437 with self.db_input_cache_lock:
438 438 try:
439 439 self._writeout_input_cache(conn)
440 440 except sqlite3.IntegrityError:
441 441 self.new_session(conn)
442 442 print("ERROR! Session/line number was not unique in",
443 443 "database. History logging moved to new session",
444 444 self.session_number)
445 445 try: # Try writing to the new session. If this fails, don't recurse
446 446 self._writeout_input_cache(conn)
447 447 except sqlite3.IntegrityError:
448 448 pass
449 449 finally:
450 450 self.db_input_cache = []
451 451
452 452 with self.db_output_cache_lock:
453 453 try:
454 454 self._writeout_output_cache(conn)
455 455 except sqlite3.IntegrityError:
456 456 print("!! Session/line number for output was not unique",
457 457 "in database. Output will not be stored.")
458 458 finally:
459 459 self.db_output_cache = []
460 460
461 461
462 462 class HistorySavingThread(threading.Thread):
463 463 """This thread takes care of writing history to the database, so that
464 464 the UI isn't held up while that happens.
465 465
466 466 It waits for the HistoryManager's save_flag to be set, then writes out
467 467 the history cache. The main thread is responsible for setting the flag when
468 468 the cache size reaches a defined threshold."""
469 469 daemon = True
470 470 stop_now = False
471 471 def __init__(self, history_manager):
472 472 super(HistorySavingThread, self).__init__()
473 473 self.history_manager = history_manager
474 474 atexit.register(self.stop)
475 475
476 476 def run(self):
477 477 # We need a separate db connection per thread:
478 478 try:
479 479 self.db = sqlite3.connect(self.history_manager.hist_file)
480 480 while True:
481 481 self.history_manager.save_flag.wait()
482 482 if self.stop_now:
483 483 return
484 484 self.history_manager.save_flag.clear()
485 485 self.history_manager.writeout_cache(self.db)
486 486 except Exception as e:
487 487 print(("The history saving thread hit an unexpected error (%s)."
488 488 "History will not be written to the database.") % repr(e))
489 489
490 490 def stop(self):
491 491 """This can be called from the main thread to safely stop this thread.
492 492
493 493 Note that it does not attempt to write out remaining history before
494 494 exiting. That should be done by calling the HistoryManager's
495 495 end_session method."""
496 496 self.stop_now = True
497 497 self.history_manager.save_flag.set()
498 498 self.join()
499 499
500 500
501 501 # To match, e.g. ~5/8-~2/3
502 502 range_re = re.compile(r"""
503 503 ((?P<startsess>~?\d+)/)?
504 504 (?P<start>\d+) # Only the start line num is compulsory
505 505 ((?P<sep>[\-:])
506 506 ((?P<endsess>~?\d+)/)?
507 507 (?P<end>\d+))?
508 508 $""", re.VERBOSE)
509 509
510 510 def extract_hist_ranges(ranges_str):
511 511 """Turn a string of history ranges into 3-tuples of (session, start, stop).
512 512
513 513 Examples
514 514 --------
515 515 list(extract_input_ranges("~8/5-~7/4 2"))
516 516 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
517 517 """
518 518 for range_str in ranges_str.split():
519 519 rmatch = range_re.match(range_str)
520 520 if not rmatch:
521 521 continue
522 522 start = int(rmatch.group("start"))
523 523 end = rmatch.group("end")
524 524 end = int(end) if end else start+1 # If no end specified, get (a, a+1)
525 525 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
526 526 end += 1
527 527 startsess = rmatch.group("startsess") or "0"
528 528 endsess = rmatch.group("endsess") or startsess
529 529 startsess = int(startsess.replace("~","-"))
530 530 endsess = int(endsess.replace("~","-"))
531 531 assert endsess >= startsess
532 532
533 533 if endsess == startsess:
534 534 yield (startsess, start, end)
535 535 continue
536 536 # Multiple sessions in one range:
537 537 yield (startsess, start, None)
538 538 for sess in range(startsess+1, endsess):
539 539 yield (sess, 1, None)
540 540 yield (endsess, 1, end)
541 541
542 542 def _format_lineno(session, line):
543 543 """Helper function to format line numbers properly."""
544 544 if session == 0:
545 545 return str(line)
546 546 return "%s#%s" % (session, line)
547 547
548 548 @skip_doctest
549 549 def magic_history(self, parameter_s = ''):
550 550 """Print input history (_i<n> variables), with most recent last.
551 551
552 552 %history -> print at most 40 inputs (some may be multi-line)\\
553 553 %history n -> print at most n inputs\\
554 554 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
555 555
556 556 By default, input history is printed without line numbers so it can be
557 557 directly pasted into an editor. Use -n to show them.
558 558
559 559 Ranges of history can be indicated using the syntax:
560 560 4 : Line 4, current session
561 561 4-6 : Lines 4-6, current session
562 562 243/1-5: Lines 1-5, session 243
563 563 ~2/7 : Line 7, session 2 before current
564 564 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
565 565 of 6 sessions ago.
566 566 Multiple ranges can be entered, separated by spaces
567 567
568 568 The same syntax is used by %macro, %save, %edit, %rerun
569 569
570 570 Options:
571 571
572 572 -n: print line numbers for each input.
573 573 This feature is only available if numbered prompts are in use.
574 574
575 575 -o: also print outputs for each input.
576 576
577 577 -p: print classic '>>>' python prompts before each input. This is useful
578 578 for making documentation, and in conjunction with -o, for producing
579 579 doctest-ready output.
580 580
581 581 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
582 582
583 583 -t: print the 'translated' history, as IPython understands it. IPython
584 584 filters your input and converts it all into valid Python source before
585 585 executing it (things like magics or aliases are turned into function
586 586 calls, for example). With this option, you'll see the native history
587 587 instead of the user-entered version: '%cd /' will be seen as
588 588 'get_ipython().magic("%cd /")' instead of '%cd /'.
589 589
590 590 -g: treat the arg as a pattern to grep for in (full) history.
591 591 This includes the saved history (almost all commands ever written).
592 592 Use '%hist -g' to show full saved history (may be very long).
593 593
594 594 -l: get the last n lines from all sessions. Specify n as a single arg, or
595 595 the default is the last 10 lines.
596 596
597 597 -f FILENAME: instead of printing the output to the screen, redirect it to
598 598 the given file. The file is always overwritten, though IPython asks for
599 599 confirmation first if it already exists.
600 600
601 601 Examples
602 602 --------
603 603 ::
604 604
605 605 In [6]: %hist -n 4 6
606 606 4:a = 12
607 607 5:print a**2
608 608
609 609 """
610 610
611 611 if not self.shell.displayhook.do_full_cache:
612 612 print('This feature is only available if numbered prompts are in use.')
613 613 return
614 614 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
615 615
616 616 # For brevity
617 617 history_manager = self.shell.history_manager
618 618
619 619 def _format_lineno(session, line):
620 620 """Helper function to format line numbers properly."""
621 621 if session in (0, history_manager.session_number):
622 622 return str(line)
623 623 return "%s/%s" % (session, line)
624 624
625 625 # Check if output to specific file was requested.
626 626 try:
627 627 outfname = opts['f']
628 628 except KeyError:
629 629 outfile = io.stdout # default
630 630 # We don't want to close stdout at the end!
631 631 close_at_end = False
632 632 else:
633 633 if os.path.exists(outfname):
634 634 if not io.ask_yes_no("File %r exists. Overwrite?" % outfname):
635 635 print('Aborting.')
636 636 return
637 637
638 638 outfile = open(outfname,'w')
639 639 close_at_end = True
640 640
641 641 print_nums = 'n' in opts
642 642 get_output = 'o' in opts
643 643 pyprompts = 'p' in opts
644 644 # Raw history is the default
645 645 raw = not('t' in opts)
646 646
647 647 default_length = 40
648 648 pattern = None
649 649
650 650 if 'g' in opts: # Glob search
651 651 pattern = "*" + args + "*" if args else "*"
652 652 hist = history_manager.search(pattern, raw=raw, output=get_output)
653 653 print_nums = True
654 654 elif 'l' in opts: # Get 'tail'
655 655 try:
656 656 n = int(args)
657 657 except ValueError, IndexError:
658 658 n = 10
659 659 hist = history_manager.get_tail(n, raw=raw, output=get_output)
660 660 else:
661 661 if args: # Get history by ranges
662 662 hist = history_manager.get_range_by_str(args, raw, get_output)
663 663 else: # Just get history for the current session
664 664 hist = history_manager.get_range(raw=raw, output=get_output)
665 665
666 666 # We could be displaying the entire history, so let's not try to pull it
667 667 # into a list in memory. Anything that needs more space will just misalign.
668 668 width = 4
669 669
670 670 for session, lineno, inline in hist:
671 671 # Print user history with tabs expanded to 4 spaces. The GUI clients
672 672 # use hard tabs for easier usability in auto-indented code, but we want
673 673 # to produce PEP-8 compliant history for safe pasting into an editor.
674 674 if get_output:
675 675 inline, output = inline
676 676 inline = inline.expandtabs(4).rstrip()
677 677
678 678 multiline = "\n" in inline
679 679 line_sep = '\n' if multiline else ' '
680 680 if print_nums:
681 681 print('%s:%s' % (_format_lineno(session, lineno).rjust(width),
682 682 line_sep), file=outfile, end='')
683 683 if pyprompts:
684 684 print(">>> ", end="", file=outfile)
685 685 if multiline:
686 686 inline = "\n... ".join(inline.splitlines()) + "\n..."
687 687 print(inline, file=outfile)
688 688 if get_output and output:
689 689 print(output, file=outfile)
690 690
691 691 if close_at_end:
692 692 outfile.close()
693 693
694 694
695 695 def magic_rep(self, arg):
696 r"""Repeat a command, or get command to input line for editing
696 r"""Repeat a command, or get command to input line for editing. %recall and
697 %rep are equivalent.
697 698
698 - %rep (no arguments):
699 - %recall (no arguments):
699 700
700 701 Place a string version of last computation result (stored in the special '_'
701 702 variable) to the next input prompt. Allows you to create elaborate command
702 703 lines without using copy-paste::
703 704
704 705 In[1]: l = ["hei", "vaan"]
705 706 In[2]: "".join(l)
706 707 Out[2]: heivaan
707 708 In[3]: %rep
708 709 In[4]: heivaan_ <== cursor blinking
709 710
710 %rep 45
711 %recall 45
711 712
712 713 Place history line 45 on the next input prompt. Use %hist to find
713 714 out the number.
714 715
715 %rep 1-4
716 %recall 1-4
716 717
717 718 Combine the specified lines into one cell, and place it on the next
718 719 input prompt. See %history for the slice syntax.
719 720
720 %rep foo+bar
721 %recall foo+bar
721 722
722 723 If foo+bar can be evaluated in the user namespace, the result is
723 724 placed at the next input prompt. Otherwise, the history is searched
724 725 for lines which contain that substring, and the most recent one is
725 726 placed at the next input prompt.
726 727 """
727 728 if not arg: # Last output
728 729 self.set_next_input(str(self.shell.user_ns["_"]))
729 730 return
730 731 # Get history range
731 732 histlines = self.history_manager.get_range_by_str(arg)
732 733 cmd = "\n".join(x[2] for x in histlines)
733 734 if cmd:
734 735 self.set_next_input(cmd.rstrip())
735 736 return
736 737
737 738 try: # Variable in user namespace
738 739 cmd = str(eval(arg, self.shell.user_ns))
739 740 except Exception: # Search for term in history
740 741 histlines = self.history_manager.search("*"+arg+"*")
741 742 for h in reversed([x[2] for x in histlines]):
742 743 if 'rep' in h:
743 744 continue
744 745 self.set_next_input(h.rstrip())
745 746 return
746 747 else:
747 748 self.set_next_input(cmd.rstrip())
748 749 print("Couldn't evaluate or find in history:", arg)
749 750
750 751 def magic_rerun(self, parameter_s=''):
751 752 """Re-run previous input
752 753
753 754 By default, you can specify ranges of input history to be repeated
754 755 (as with %history). With no arguments, it will repeat the last line.
755 756
756 757 Options:
757 758
758 759 -l <n> : Repeat the last n lines of input, not including the
759 760 current command.
760 761
761 762 -g foo : Repeat the most recent line which contains foo
762 763 """
763 764 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
764 765 if "l" in opts: # Last n lines
765 766 n = int(opts['l'])
766 767 hist = self.history_manager.get_tail(n)
767 768 elif "g" in opts: # Search
768 769 p = "*"+opts['g']+"*"
769 770 hist = list(self.history_manager.search(p))
770 771 for l in reversed(hist):
771 772 if "rerun" not in l[2]:
772 773 hist = [l] # The last match which isn't a %rerun
773 774 break
774 775 else:
775 776 hist = [] # No matches except %rerun
776 777 elif args: # Specify history ranges
777 778 hist = self.history_manager.get_range_by_str(args)
778 779 else: # Last line
779 780 hist = self.history_manager.get_tail(1)
780 781 hist = [x[2] for x in hist]
781 782 if not hist:
782 783 print("No lines in history match specification")
783 784 return
784 785 histlines = "\n".join(hist)
785 786 print("=== Executing: ===")
786 787 print(histlines)
787 788 print("=== Output: ===")
788 789 self.run_cell("\n".join(hist), store_history=False)
789 790
790 791
791 792 def init_ipython(ip):
792 793 ip.define_magic("rep", magic_rep)
793 794 ip.define_magic("recall", magic_rep)
794 795 ip.define_magic("rerun", magic_rerun)
795 796 ip.define_magic("hist",magic_history) # Alternative name
796 797 ip.define_magic("history",magic_history)
797 798
798 799 # XXX - ipy_completers are in quarantine, need to be updated to new apis
799 800 #import ipy_completers
800 801 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
General Comments 0
You need to be logged in to leave comments. Login now