diff options
author | Pablo Galindo Salgado <Pablogsal@gmail.com> | 2024-05-07 12:54:56 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-07 12:54:56 (GMT) |
commit | 7d90b8aadbd6993ee50a73b7536f769334718423 (patch) | |
tree | c52e6f2f5f03a3e2a6b4f57a5b2a0e321c72000a | |
parent | ad3d877a126bc892d1c598cf1357a2c39fd466c7 (diff) | |
download | cpython-7d90b8aadbd6993ee50a73b7536f769334718423.zip cpython-7d90b8aadbd6993ee50a73b7536f769334718423.tar.gz cpython-7d90b8aadbd6993ee50a73b7536f769334718423.tar.bz2 |
gh-111201: Allow bracketed paste to work (GH-118700)
-rw-r--r-- | Lib/_pyrepl/commands.py | 10 | ||||
-rw-r--r-- | Lib/_pyrepl/reader.py | 2 | ||||
-rw-r--r-- | Lib/_pyrepl/unix_console.py | 9 | ||||
-rw-r--r-- | Lib/test/test_pyrepl.py | 40 |
4 files changed, 61 insertions, 0 deletions
diff --git a/Lib/_pyrepl/commands.py b/Lib/_pyrepl/commands.py index 60ceb30..bb6bebac 100644 --- a/Lib/_pyrepl/commands.py +++ b/Lib/_pyrepl/commands.py @@ -462,3 +462,13 @@ class paste_mode(Command): def do(self) -> None: self.reader.paste_mode = not self.reader.paste_mode self.reader.dirty = True + + +class enable_bracketed_paste(Command): + def do(self) -> None: + self.reader.paste_mode = True + +class disable_bracketed_paste(Command): + def do(self) -> None: + self.reader.paste_mode = False + self.reader.insert("\n") diff --git a/Lib/_pyrepl/reader.py b/Lib/_pyrepl/reader.py index 071dfe5..e36f65c 100644 --- a/Lib/_pyrepl/reader.py +++ b/Lib/_pyrepl/reader.py @@ -127,6 +127,8 @@ default_keymap: tuple[tuple[KeySpec, CommandName], ...] = tuple( (r"\M-9", "digit-arg"), # (r'\M-\n', 'insert-nl'), ("\\\\", "self-insert"), + (r"\x1b[200~", "enable_bracketed_paste"), + (r"\x1b[201~", "disable_bracketed_paste"), ] + [(c, "self-insert") for c in map(chr, range(32, 127)) if c != "\\"] + [(c, "self-insert") for c in map(chr, range(128, 256)) if c.isalpha()] diff --git a/Lib/_pyrepl/unix_console.py b/Lib/_pyrepl/unix_console.py index c22b1d5..605318c 100644 --- a/Lib/_pyrepl/unix_console.py +++ b/Lib/_pyrepl/unix_console.py @@ -336,10 +336,13 @@ class UnixConsole(Console): except ValueError: pass + self.__enable_bracketed_paste() + def restore(self): """ Restore the console to the default state """ + self.__disable_bracketed_paste() self.__maybe_write_code(self._rmkx) self.flushoutput() tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate) @@ -525,6 +528,12 @@ class UnixConsole(Console): self.__posxy = 0, 0 self.screen = [] + def __enable_bracketed_paste(self) -> None: + os.write(self.output_fd, b"\x1b[?2004h") + + def __disable_bracketed_paste(self) -> None: + os.write(self.output_fd, b"\x1b[?2004l") + def __setup_movement(self): """ Set up the movement functions based on the terminal capabilities. diff --git a/Lib/test/test_pyrepl.py b/Lib/test/test_pyrepl.py index 3df76e0..b7ae91b 100644 --- a/Lib/test/test_pyrepl.py +++ b/Lib/test/test_pyrepl.py @@ -817,6 +817,46 @@ class TestPasteEvent(TestCase): output = multiline_input(reader) self.assertEqual(output, output_code) + def test_bracketed_paste(self): + """Test that bracketed paste using \x1b[200~ and \x1b[201~ works.""" + # fmt: off + input_code = ( + 'def a():\n' + ' for x in range(10):\n' + '\n' + ' if x%2:\n' + ' print(x)\n' + '\n' + ' else:\n' + ' pass\n' + ) + # fmt: on + + output_code = ( + 'def a():\n' + ' for x in range(10):\n' + '\n' + ' if x%2:\n' + ' print(x)\n' + '\n' + ' else:\n' + ' pass\n' + '\n' + ) + + paste_start = "\x1b[200~" + paste_end = "\x1b[201~" + + events = itertools.chain( + code_to_events(paste_start), + code_to_events(input_code), + code_to_events(paste_end), + code_to_events("\n"), + ) + reader = self.prepare_reader(events) + output = multiline_input(reader) + self.assertEqual(output, output_code) + class TestReader(TestCase): def assert_screen_equals(self, reader, expected): |