Repository: xonsh/xonsh

Issue:
EOF in multi-line string (always; without EOF)
The second hit of return in a multiline string consistently results in a "SyntaxError: EOF in multiline string": 

``` sh
$ a = """<CR>
<CR>
Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/xonsh/__amalgam__.py", line 16049, in _parse_ctx_free
    debug_level=(self.debug_level > 1))
  File "/usr/lib/python3.5/site-packages/xonsh/parsers/base.py", line 310, in parse
    tree = self.parser.parse(input=s, lexer=self.lexer, debug=debug_level)
  File "/usr/lib/python3.5/site-packages/ply/yacc.py", line 331, in parse
    return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
  File "/usr/lib/python3.5/site-packages/ply/yacc.py", line 1181, in parseopt_notrack
    tok = call_errorfunc(self.errorfunc, errtoken, self)
  File "/usr/lib/python3.5/site-packages/ply/yacc.py", line 193, in call_errorfunc
    r = errorfunc(token)
  File "/usr/lib/python3.5/site-packages/xonsh/parsers/base.py", line 2337, in p_error
    self.xonsh_code)
  File "/usr/lib/python3.5/site-packages/xonsh/parsers/base.py", line 411, in _parse_error
    raise err
  File "<string>", line None
SyntaxError: <xonsh-code>:2:9: Unmatched "]" at line 2, column 9
![a = """]
         ^

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/xonsh/ptk/shell.py", line 100, in push
    locs=None)
  File "/usr/lib/python3.5/site-packages/xonsh/__amalgam__.py", line 15996, in compile
    tree = self.parse(input, ctx, mode=mode, transform=transform)
  File "/usr/lib/python3.5/site-packages/xonsh/__amalgam__.py", line 15967, in parse
    tree, input = self._parse_ctx_free(input, mode=mode)
  File "/usr/lib/python3.5/site-packages/xonsh/__amalgam__.py", line 16107, in _parse_ctx_free
    raise original_error
  File "/usr/lib/python3.5/site-packages/xonsh/__amalgam__.py", line 16049, in _parse_ctx_free
    debug_level=(self.debug_level > 1))
  File "/usr/lib/python3.5/site-packages/xonsh/parsers/base.py", line 310, in parse
    tree = self.parser.parse(input=s, lexer=self.lexer, debug=debug_level)
  File "/usr/lib/python3.5/site-packages/ply/yacc.py", line 331, in parse
    return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
  File "/usr/lib/python3.5/site-packages/ply/yacc.py", line 1181, in parseopt_notrack
    tok = call_errorfunc(self.errorfunc, errtoken, self)
  File "/usr/lib/python3.5/site-packages/ply/yacc.py", line 193, in call_errorfunc
    r = errorfunc(token)
  File "/usr/lib/python3.5/site-packages/xonsh/parsers/base.py", line 2337, in p_error
    self.xonsh_code)
  File "/usr/lib/python3.5/site-packages/xonsh/parsers/base.py", line 411, in _parse_error
    raise err
  File "<string>", line None
SyntaxError: <xonsh-code>:0:0: EOF in multi-line string
a = """
^
$ xonsh --version
('xonsh/0.4.4',)
$ uname -r
4.7.0-1-ARCH
```



Discussion:
thanks for reporthing this @OJFord! i think this is annoying and definitely something we should fix.


Resolving patch:
diff --git a/xonsh/base_shell.py b/xonsh/base_shell.py
--- a/xonsh/base_shell.py
+++ b/xonsh/base_shell.py
@@ -7,7 +7,7 @@
 import builtins
 
 from xonsh.tools import (XonshError, escape_windows_cmd_string, print_exception,
-                         DefaultNotGiven)
+                         DefaultNotGiven, check_for_partial_string)
 from xonsh.platform import HAS_PYGMENTS, ON_WINDOWS
 from xonsh.codecache import (should_use_cache, code_cache_name,
                              code_cache_check, get_cache_filename,
@@ -209,7 +209,10 @@ def push(self, line):
                 update_cache(code, cachefname)
             self.reset_buffer()
         except SyntaxError:
-            if line == '\n':
+            partial_string_info = check_for_partial_string(src)
+            in_partial_string = (partial_string_info[0] is not None and
+                                 partial_string_info[1] is None)
+            if ((line == '\n' and not in_partial_string)):
                 self.reset_buffer()
                 print_exception()
                 return src, None
diff --git a/xonsh/ptk/key_bindings.py b/xonsh/ptk/key_bindings.py
--- a/xonsh/ptk/key_bindings.py
+++ b/xonsh/ptk/key_bindings.py
@@ -8,7 +8,7 @@
                                     ViInsertMode)
 from prompt_toolkit.keys import Keys
 from xonsh.aliases import xonsh_exit
-from xonsh.tools import ON_WINDOWS
+from xonsh.tools import ON_WINDOWS, check_for_partial_string
 
 env = builtins.__xonsh_env__
 DEDENT_TOKENS = frozenset(['raise', 'return', 'pass', 'break', 'continue'])
@@ -34,6 +34,10 @@ def carriage_return(b, cli, *, autoindent=True):
 
     indent = env.get('INDENT') if autoindent else ''
 
+    partial_string_info = check_for_partial_string(doc.text)
+    in_partial_string = (partial_string_info[0] is not None and
+                         partial_string_info[1] is None)
+
     # indent after a colon
     if (doc.current_line_before_cursor.strip().endswith(':') and
             at_end_of_line):
@@ -59,6 +63,8 @@ def carriage_return(b, cli, *, autoindent=True):
         b.newline(copy_margin=autoindent)
     elif not current_line_blank and not can_compile(doc.text):
         b.newline(copy_margin=autoindent)
+    elif current_line_blank and in_partial_string:
+        b.newline(copy_margin=autoindent)
     else:
         b.accept_action.validate_and_handle(cli, b)
 


Test patch: