Repository: xonsh/xonsh

Issue:
unresponsive after: time.time() | grep "exit"
If I run:

``` python
import time
time.time() | grep "exit"
```

I fully understand that this is a misguided series of commands (trying to mix python mode and subprocess mode). However the fact that it makes my terminal unresponsive and unrecoverable (Ctrl+C and Ctrl+Z do nothing) seems undesirable. 

I'm using prompt-toolkit.



Discussion:
Thanks for reporting this @JohnLunzer! I can reproduce this, but this is actually a pretty weird corner case.  It is hanging because `grep "exit"` will hang (since you didn't provide any files as input).  The hanging is totally normal.

The unexpected thing is that it is unrecoverable.  On master I am able to Crtl-C out of this like I would normally Crlt-C out of a hanging grep command.  What version of xonsh or you on: 0.2.7 or master? 

I'm using the conda bleeding edge version, here is my xonfig:

```
+------------------+-------+
| xonsh            | 0.2.7 |
| Python           | 3.5.1 |
| PLY              | 3.7   |
| have readline    | True  |
| prompt toolkit   | 1.0.0 |
| pygments         | 2.0.2 |
| on posix         | True  |
| on linux         | True  |
| on arch          | False |
| on windows       | False |
| on mac           | False |
| are root user    | False |
| default encoding | utf-8 |
+------------------+-------+
```

I'm using gnome-terminal. The unrecoverable hanging happens inside and outside Tmux. When I type `grep "exit"` by itself the title of the terminal window changes to grep and then I can exit out of it with Ctrl + C. but with `time.time() | grep "exit"` the title of the terminal window does not change and additionally the xonsh python process is using 100% of one CPU core (seen via htop from another non xonsh terminal). 

I experience your behavior (able to use Ctrl + C) if I use `$SHELL_TYPE = 'readline'`. But if I am using prompt-toolkit then I can no longer enter any input including Ctrl + C.

Hope this is enough information to fully reproduce what I'm seeing.

Ahh you are totally right, I can reproduce this on PTK.


Resolving patch:
diff --git a/xonsh/execer.py b/xonsh/execer.py
--- a/xonsh/execer.py
+++ b/xonsh/execer.py
@@ -204,7 +204,8 @@ def _parse_ctx_free(self, input, mode='exec'):
                     else:
                         # or for some other syntax error
                         raise original_error
-                elif sbpline.lstrip().startswith('![!['):
+                elif sbpline[last_error_col:].startswith('![![') or \
+                     sbpline.lstrip().startswith('![!['):
                     # if we have already wrapped this in subproc tokens
                     # and it still doesn't work, adding more won't help
                     # anything


Test patch:
diff --git a/tests/test_execer.py b/tests/test_execer.py
--- a/tests/test_execer.py
+++ b/tests/test_execer.py
@@ -83,6 +83,16 @@ def test_bad_indent():
             'x = 1\n')
     assert_raises(SyntaxError, check_parse, code)
 
+def test_good_rhs_subproc():
+    # nonsense but parsebale
+    code = 'str().split() | ![grep exit]\n'
+    check_parse(code)
+
+def test_bad_rhs_subproc():
+    # nonsense but unparsebale
+    code = 'str().split() | grep exit\n'
+    assert_raises(SyntaxError, check_parse, code)
+
 def test_indent_with_empty_line():
     code = ('if True:\n'
             '\n'