Repository: ipython/ipython

Issue:
paste into ipython stop working with vi mode
this works well:

```
[ins] In [46]: In [41]: s = 'Abc Def Ghi'
[ins] In [47]:
```

this does not work.
```
[ins] In [44]: [ins] In [41]: s = 'Abc Def Ghi'                       
          ...:                 
          ...:                                                        
  File "<ipython-input-44-0af6a6a3f6c4>", line 1
    [ins] In [41]: s = 'Abc Def Ghi'
          ^
SyntaxError: invalid syntax
```

is it possible to configure ipython to also accept transcript under vi mode?


Discussion:
Nice catch. I was pondering whether it's a bug - it seems like an omission of sorts, rather than an all out error - but I'm not sure if you are supposed to select text while in the insert mode. As a Vim user, It feels weird to me to go into insert mode then start to select text by mouse and copy it.

Then again insert mode is the default, and the nav mode has its own prompt too, smarter pasting shouldn't be hard to implement for either.


Resolving patch:
diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py
--- a/IPython/core/inputtransformer2.py
+++ b/IPython/core/inputtransformer2.py
@@ -89,7 +89,30 @@ def __call__(self, lines):
     initial_re=re.compile(r'^>>>( |$)')
 )
 
-ipython_prompt = PromptStripper(re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)'))
+ipython_prompt = PromptStripper(
+    re.compile(
+        r"""
+        ^(                         # Match from the beginning of a line, either:
+
+                                   # 1. First-line prompt:
+        ((\[nav\]|\[ins\])?\ )?    # Vi editing mode prompt, if it's there
+        In\                        # The 'In' of the prompt, with a space
+        \[\d+\]:                   # Command index, as displayed in the prompt
+        \                          # With a mandatory trailing space
+
+        |                          # ... or ...
+
+                                   # 2. The three dots of the multiline prompt
+        \s*                        # All leading whitespace characters
+        \.{3,}:                    # The three (or more) dots
+        \ ?                        # With an optional trailing space
+
+        )
+        """,
+        re.VERBOSE,
+    )
+)
+
 
 def cell_magic(lines):
     if not lines or not lines[0].startswith('%%'):


Test patch:
diff --git a/IPython/core/tests/test_inputtransformer2_line.py b/IPython/core/tests/test_inputtransformer2_line.py
--- a/IPython/core/tests/test_inputtransformer2_line.py
+++ b/IPython/core/tests/test_inputtransformer2_line.py
@@ -61,10 +61,50 @@ def test_classic_prompt():
     print(a ** 2)
 """)
 
+
+IPYTHON_PROMPT_VI_INS = (
+    """\
+[ins] In [11]: def a():
+          ...:     123
+          ...:
+          ...: 123
+""",
+    """\
+def a():
+    123
+
+123
+""",
+)
+
+IPYTHON_PROMPT_VI_NAV = (
+    """\
+[nav] In [11]: def a():
+          ...:     123
+          ...:
+          ...: 123
+""",
+    """\
+def a():
+    123
+
+123
+""",
+)
+
+
 def test_ipython_prompt():
-    for sample, expected in [IPYTHON_PROMPT, IPYTHON_PROMPT_L2]:
-        nt.assert_equal(ipt2.ipython_prompt(sample.splitlines(keepends=True)),
-                        expected.splitlines(keepends=True))
+    for sample, expected in [
+        IPYTHON_PROMPT,
+        IPYTHON_PROMPT_L2,
+        IPYTHON_PROMPT_VI_INS,
+        IPYTHON_PROMPT_VI_NAV,
+    ]:
+        nt.assert_equal(
+            ipt2.ipython_prompt(sample.splitlines(keepends=True)),
+            expected.splitlines(keepends=True),
+        )
+
 
 INDENT_SPACES = ("""\
      if True:
@@ -123,4 +163,4 @@ def test_leading_empty_lines():
 
 def test_crlf_magic():
     for sample, expected in [CRLF_MAGIC]:
-        nt.assert_equal(ipt2.cell_magic(sample), expected)
\ No newline at end of file
+        nt.assert_equal(ipt2.cell_magic(sample), expected)