diff --git a/IPython/core/inputsplitter.py b/IPython/core/inputsplitter.py index 640465d..424aa79 100644 --- a/IPython/core/inputsplitter.py +++ b/IPython/core/inputsplitter.py @@ -658,6 +658,34 @@ def transform_ipy_prompt(line): return line +def _make_help_call(target, esc, lspace): + """Prepares a pinfo(2)/psearch call from a target name and the escape + (i.e. ? or ??)""" + method = 'pinfo2' if esc == '??' \ + else 'psearch' if '*' in target \ + else 'pinfo' + + tpl = '%sget_ipython().magic(u"%s %s")' + return tpl % (lspace, method, target) + +_initial_space_re = re.compile(r'\s*') +_help_end_re = re.compile(r"""(%? + [a-zA-Z_*][a-zA-Z0-9_*]* # Variable name + (.[a-zA-Z_*][a-zA-Z0-9_*]*)* # .etc.etc + ) + (\?\??)$ # ? or ??""", + re.VERBOSE) +def transform_help_end(line): + """Translate lines with ?/?? at the end""" + m = _help_end_re.search(line) + if m is None: + return line + target = m.group(1) + esc = m.group(3) + lspace = _initial_space_re.match(line).group(0) + return _make_help_call(target, esc, lspace) + + class EscapedTransformer(object): """Class to transform lines that are explicitly escaped out.""" @@ -694,28 +722,8 @@ class EscapedTransformer(object): # A naked help line should just fire the intro help screen if not line_info.line[1:]: return 'get_ipython().show_usage()' - - # There may be one or two '?' at the end, move them to the front so that - # the rest of the logic can assume escapes are at the start - l_ori = line_info - line = line_info.line - if line.endswith('?'): - line = line[-1] + line[:-1] - if line.endswith('?'): - line = line[-1] + line[:-1] - line_info = LineInfo(line) - - # From here on, simply choose which level of detail to get, and - # special-case the psearch syntax - pinfo = 'pinfo' # default - if '*' in line_info.line: - pinfo = 'psearch' - elif line_info.esc == '??': - pinfo = 'pinfo2' - - tpl = '%sget_ipython().magic(u"%s %s")' - return tpl % (line_info.lspace, pinfo, - ' '.join([line_info.fpart, line_info.rest]).strip()) + + return _make_help_call(line_info.fpart, line_info.esc, line_info.lspace) @staticmethod def _tr_magic(line_info): @@ -756,14 +764,9 @@ class EscapedTransformer(object): # Get line endpoints, where the escapes can be line_info = LineInfo(line) - # If the escape is not at the start, only '?' needs to be special-cased. - # All other escapes are only valid at the start if not line_info.esc in self.tr: - if line.endswith(ESC_HELP): - return self._tr_help(line_info) - else: - # If we don't recognize the escape, don't modify the line - return line + # If we don't recognize the escape, don't modify the line + return line return self.tr[line_info.esc](line_info) @@ -815,9 +818,9 @@ class IPythonInputSplitter(InputSplitter): lines_list = lines.splitlines() - transforms = [transform_escaped, transform_assign_system, - transform_assign_magic, transform_ipy_prompt, - transform_classic_prompt] + transforms = [transform_escaped, transform_help_end, + transform_assign_system, transform_assign_magic, + transform_ipy_prompt, transform_classic_prompt] # Transform logic # diff --git a/IPython/core/tests/test_inputsplitter.py b/IPython/core/tests/test_inputsplitter.py index 95ebc20..c32068e 100644 --- a/IPython/core/tests/test_inputsplitter.py +++ b/IPython/core/tests/test_inputsplitter.py @@ -434,12 +434,21 @@ syntax = \ [ ('?', 'get_ipython().show_usage()'), ('?x1', 'get_ipython().magic(u"pinfo x1")'), ('??x2', 'get_ipython().magic(u"pinfo2 x2")'), - ('x3?', 'get_ipython().magic(u"pinfo x3")'), - ('x4??', 'get_ipython().magic(u"pinfo2 x4")'), - ('%hist?', 'get_ipython().magic(u"pinfo %hist")'), - ('f*?', 'get_ipython().magic(u"psearch f*")'), - ('ax.*aspe*?', 'get_ipython().magic(u"psearch ax.*aspe*")'), + ('?a.*s', 'get_ipython().magic(u"psearch a.*s")'), + ('?%hist', 'get_ipython().magic(u"pinfo %hist")'), + ('?abc = qwe', 'get_ipython().magic(u"pinfo abc")'), ], + + end_help = + [ ('x3?', 'get_ipython().magic(u"pinfo x3")'), + ('x4??', 'get_ipython().magic(u"pinfo2 x4")'), + ('%hist?', 'get_ipython().magic(u"pinfo %hist")'), + ('f*?', 'get_ipython().magic(u"psearch f*")'), + ('ax.*aspe*?', 'get_ipython().magic(u"psearch ax.*aspe*")'), + ('a = abc?', 'get_ipython().magic(u"pinfo abc")'), + ('a = abc.qe??', 'get_ipython().magic(u"pinfo2 abc.qe")'), + ('a = *.items?', 'get_ipython().magic(u"psearch *.items")'), + ], # Explicit magic calls escaped_magic = @@ -513,7 +522,9 @@ def test_ipy_prompt(): transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt) for example in syntax_ml['ipy_prompt']: transform_checker(example, isp.transform_ipy_prompt) - + +def test_end_help(): + transform_checker(syntax['end_help'], isp.transform_help_end) def test_escaped_noesc(): transform_checker(syntax['escaped_noesc'], isp.transform_escaped)