diff --git a/IPython/core/history.py b/IPython/core/history.py index 73a1c1b..7b5839a 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -202,7 +202,8 @@ class HistoryManager(Configurable): (n,), raw=raw, output=output) return reversed(list(cur)) - def get_hist_search(self, pattern="*", raw=True, output=False): + def get_hist_search(self, pattern="*", raw=True, search_raw=True, + output=False): """Search the database using unix glob-style matching (wildcards * and ?, escape using \). @@ -210,7 +211,7 @@ class HistoryManager(Configurable): ------- An iterator over tuples: (session, line_number, command) """ - tosearch = "source_raw" if raw else "source" + tosearch = "source_raw" if search_raw else "source" if output: tosearch = "history." + tosearch self.writeout_cache() @@ -307,13 +308,15 @@ class HistoryManager(Configurable): """ if source_raw is None: source_raw = source + source = source.rstrip() + source_raw = source_raw.rstrip() # do not store exit/quit commands if source_raw.strip() in self._exit_commands: return - self.input_hist_parsed.append(source.rstrip()) - self.input_hist_raw.append(source_raw.rstrip()) + self.input_hist_parsed.append(source) + self.input_hist_raw.append(source_raw) self.db_input_cache.append((self.session_number, line_num, source, source_raw)) @@ -556,59 +559,95 @@ def magic_rep(self, arg): variable) to the next input prompt. Allows you to create elaborate command lines without using copy-paste:: - $ l = ["hei", "vaan"] - $ "".join(l) - ==> heivaan - $ %rep - $ heivaan_ <== cursor blinking + In[1]: l = ["hei", "vaan"] + In[2]: "".join(l) + Out[2]: heivaan + In[3]: %rep + In[4]: heivaan_ <== cursor blinking %rep 45 - Place history line 45 to next input prompt. Use %hist to find out the - number. + Place history line 45 on the next input prompt. Use %hist to find + out the number. %rep 1-4 6-7 3 - Repeat the specified lines immediately. Input slice syntax is the same as - in %macro and %save. + Combine the specified lines into one cell, and place it on the next + input prompt. History slice syntax is the same as in %macro and %save. - %rep foo + %rep foo+bar - Place the most recent line that has the substring "foo" to next input. - (e.g. 'svn ci -m foobar'). + If foo+bar can be evaluated in the user namespace, the result is + placed at the next input prompt. Otherwise, the history is searched + for lines which contain that substring, and the most recent one is + placed at the next input prompt. """ - - opts,args = self.parse_options(arg,'',mode='list') - if not args: # Last output + if not arg: # Last output self.set_next_input(str(self.shell.user_ns["_"])) return + # Get history range + histlines = self.history_manager.get_hist_from_rangestr(arg) + cmd = "\n".join(x[2] for x in histlines) + if cmd: + self.set_next_input(cmd.rstrip()) + return - arg = " ".join(args) - histlines = self.history_manager.get_hist_from_rangestr(arg, raw=False) - histlines = [x[2] for x in histlines] - - if len(histlines) > 1: # Execute immediately - histlines = "\n".join(histlines) - print("=== Executing: ===") - print(histlines) - print("=== Output: ===") - self.run_source(histlines, symbol="exec") - - elif len(histlines) == 1: # Editable input - self.set_next_input(histlines[0].rstrip()) - - else: # Search for term - editable input + try: # Variable in user namespace + cmd = str(eval(arg, self.shell.user_ns)) + except Exception: # Search for term in history histlines = self.history_manager.get_hist_search("*"+arg+"*") for h in reversed([x[2] for x in histlines]): if 'rep' in h: continue self.set_next_input(h.rstrip()) return - print("Not found in history:", arg) + else: + self.set_next_input(cmd.rstrip()) + print("Couldn't evaluate or find in history:", arg) + +def magic_rerun(self, parameter_s=''): + """Re-run previous input + + By default, you can specify ranges of input history to be repeated + (as with %hist). With no arguments, it will repeat the last line. + + Options: + + -l : Repeat the last n lines of input, not including the + current command. + + -g foo : Repeat the most recent line which contains foo + """ + opts, args = self.parse_options(parameter_s, 'l:g:', mode='string') + if "l" in opts: # Last n lines + n = int(opts['l']) + 1 + hist = self.history_manager.get_hist_tail(n, raw=False) + elif "g" in opts: # Search + p = "*"+opts['g']+"*" + hist = self.history_manager.get_hist_search(p, raw=False) + hist = list(hist)[-2:] + elif args: # Specify history ranges + hist = self.history_manager.get_hist_from_rangestr(args) + else: # Last line + hist = self.history_manager.get_hist_tail(2, raw=False) + hist = [x[2] for x in hist] + if hist and parameter_s in hist[-1]: + hist = hist[:-1] + if not hist: + print("No lines in history match specification") + return + histlines = "\n".join(hist) + print("=== Executing: ===") + print(histlines) + print("=== Output: ===") + self.run_source("\n".join(hist), symbol="exec") def init_ipython(ip): ip.define_magic("rep", magic_rep) + ip.define_magic("recall", magic_rep) + ip.define_magic("rerun", magic_rerun) + ip.define_magic("r", magic_rerun) ip.define_magic("hist",magic_history) # Alternative name ip.define_magic("history",magic_history) diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 5601a28..224dd06 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -3029,38 +3029,6 @@ Defaulting color scheme to 'NoColor'""" if parameter_s: return self.shell.getoutput(parameter_s) - def magic_r(self, parameter_s=''): - """Repeat previous input. - - Note: Consider using the more powerfull %rep instead! - - If given an argument, repeats the previous command which starts with - the same string, otherwise it just repeats the previous input. - - Shell escaped commands (with ! as first character) are not recognized - by this system, only pure python code and magic commands. - """ - - start = parameter_s.strip() - esc_magic = ESC_MAGIC - # Identify magic commands even if automagic is on (which means - # the in-memory version is different from that typed by the user). - if self.shell.automagic: - start_magic = esc_magic+start - else: - start_magic = start - # Look through the input history in reverse - for n in range(len(self.shell.history_manager.input_hist_parsed)-2,0,-1): - input = self.shell.history_manager.input_hist_parsed[n] - # skip plain 'r' lines so we don't recurse to infinity - if input != '_ip.magic("r")\n' and \ - (input.startswith(start) or input.startswith(start_magic)): - #print 'match',`input` # dbg - print 'Executing:',input, - self.shell.run_cell(input) - return - print 'No previous input matching `%s` found.' % start - def magic_bookmark(self, parameter_s=''): """Manage IPython's bookmark system.