diff --git a/news/linecont.rst b/news/linecont.rst new file mode 100644 index 000000000..eb5f1e21e --- /dev/null +++ b/news/linecont.rst @@ -0,0 +1,24 @@ +**Added:** + +* + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* Fixed regression with line continuations in implicit subprocess mode within + indented blocks of code, such as if-statements. + +**Security:** + +* diff --git a/tests/test_execer.py b/tests/test_execer.py index 75dc205e5..22e612a6d 100644 --- a/tests/test_execer.py +++ b/tests/test_execer.py @@ -133,6 +133,7 @@ def test_echo_line_cont(): "echo a and \\\necho b\n", "echo a \\\n or echo b\n", "echo a \\\n or echo b and \\\n echo c\n", + "if True:\\\n echo a \\\n b\n", ], ) def test_two_echo_line_cont(code): diff --git a/xonsh/execer.py b/xonsh/execer.py index d46b290eb..1815a5b91 100644 --- a/xonsh/execer.py +++ b/xonsh/execer.py @@ -14,6 +14,7 @@ from xonsh.tools import ( get_logical_line, replace_logical_line, balanced_parens, + starting_whitespace, ) from xonsh.built_ins import load_builtins, unload_builtins, load_proxies, unload_proxies @@ -207,6 +208,9 @@ class Execer(object): greedy = False if filename is None: filename = self.filename + if logical_input: + beg_spaces = starting_whitespace(input) + input = input[len(beg_spaces) :] while not parsed: try: tree = self.parser.parse( @@ -313,4 +317,6 @@ class Execer(object): replace_logical_line(lines, sbpline, idx, nlogical) last_error_col += 3 input = "\n".join(lines) + if logical_input: + input = beg_spaces + input return tree, input diff --git a/xonsh/tools.py b/xonsh/tools.py index 0347cc502..58fad0323 100644 --- a/xonsh/tools.py +++ b/xonsh/tools.py @@ -616,6 +616,16 @@ def subexpr_before_unbalanced(expr, ltok, rtok): return subexpr +@lazyobject +def STARTING_WHITESPACE_RE(): + return re.compile(r"^(\s*)") + + +def starting_whitespace(s): + """Returns the whitespace at the start of a string""" + return STARTING_WHITESPACE_RE.match(s).group(1) + + def decode(s, encoding=None): encoding = encoding or DEFAULT_ENCODING return s.decode(encoding, "replace")