From d40750ec3e5734f37788e2a54bf291e4b0be79ae Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Fri, 29 Jul 2022 19:02:17 -0700 Subject: [PATCH 1/2] Strip bracketed-paste control characters from output readline adds these by default, though that default is overridden in bash and python. It is not overriden in Octave and likely other REPLs as well. --- metakernel/replwrap.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/metakernel/replwrap.py b/metakernel/replwrap.py index daa7ba7..4de060e 100644 --- a/metakernel/replwrap.py +++ b/metakernel/replwrap.py @@ -235,7 +235,7 @@ def run_command(self, command, timeout=None, stream_handler=None, for line in cmdlines[1:]: if not self.prompt_emit_cmd: self._expect_prompt(timeout=timeout) - res.append(self.child.before) + res.append(strip_bracketing(self.child.before)) self.sendline(line) # Command was fully submitted, now wait for the next prompt @@ -246,7 +246,7 @@ def run_command(self, command, timeout=None, stream_handler=None, if self._stream_handler or self._line_handler: return u'' - return u''.join(res + [self.child.before]) + return u''.join(res + [strip_bracketing(self.child.before)]) def interrupt(self, continuation=False): """Interrupt the process and wait for a prompt. @@ -322,3 +322,11 @@ def bash(command="bash", prompt_regex=re.compile('[$#]')): def powershell(command='powershell', prompt_regex='>'): """"Start a powershell and return a :class:`REPLWrapper` object.""" return REPLWrapper(command, prompt_regex, 'Function prompt {{ "{0}" }}', echo=True) + + +def strip_bracketing(string, start='\x1b[?2004l', stop='\x1b[?2004h'): + """Strip 'bracketed paste' control characters, if they are present""" + if string.startswith(start) and string.endswith(stop): + return string[len(start):-len(stop)] + else: + return string From d1cdab07812de4260a0ee8809f6f537649aa0aa1 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Fri, 29 Jul 2022 19:03:17 -0700 Subject: [PATCH 2/2] Test that bracketed paste control chars are stripped correctly --- metakernel/tests/test_replwrap.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/metakernel/tests/test_replwrap.py b/metakernel/tests/test_replwrap.py index 3d1f6d0..bb76e4f 100644 --- a/metakernel/tests/test_replwrap.py +++ b/metakernel/tests/test_replwrap.py @@ -86,6 +86,15 @@ def test_python(self): res = p.run_command('for a in range(3): print(a)\n') assert res.strip().splitlines() == ['0', '1', '2'] + def test_bracketed_paste(self): + # Readline paste bracketing is easily toggled in bash, but can be harder elsewhere + # This tests that run_command() still works with it enabled (the default for readline, + # but overriden by bash and python) + bash = replwrap.bash() + bash.run_command("bind 'set enable-bracketed-paste on'") + res = bash.run_command("echo '1 2\n3 4'") + self.assertEqual(res.strip().splitlines(), ['1 2', '3 4']) + if __name__ == '__main__': unittest.main()