diff --git a/Lib/_pyrepl/commands.py b/Lib/_pyrepl/commands.py index e79fbfa6bb0b38..6083dfe924ffd6 100644 --- a/Lib/_pyrepl/commands.py +++ b/Lib/_pyrepl/commands.py @@ -24,6 +24,10 @@ import time from typing import TYPE_CHECKING +lazy import subprocess +lazy import tempfile +lazy from pathlib import Path + # Categories of actions: # killing # yanking @@ -519,3 +523,46 @@ def do(self) -> None: s=time.time() - start, ) self.reader.insert(data.replace(done, "")) + + +class open_input_in_editor(EditCommand): + def do(self) -> None: + r = self.reader + + editor = os.environ.get("VISUAL") or os.environ.get("EDITOR") + if not editor: + editor = "vi" if os.name != "nt" else "notepad" + + with tempfile.NamedTemporaryFile( + mode="w+", suffix=".py", delete=False, encoding="utf-8" + ) as f: + tmp_path = Path(f.name) + f.write("".join(r.buffer)) + f.flush() + + try: + with r.suspend(): + cmd = editor.split() + [str(tmp_path)] + try: + subprocess.call(cmd) + except FileNotFoundError: + r.error(f"Editor not found: {editor}") + return + except Exception as e: + r.error(f"Failed to run editor: {e}") + return + + try: + new_text = tmp_path.read_text(encoding="utf-8").rstrip("\n") + r.buffer.clear() + r.buffer.extend(new_text) + r.pos = len(r.buffer) + r.invalidate_full() + r.console.repaint() + except Exception as e: + r.error(f"Failed to read edited file: {e}") + finally: + try: + tmp_path.unlink(missing_ok=True) + except Exception: + pass diff --git a/Lib/_pyrepl/reader.py b/Lib/_pyrepl/reader.py index b8e1e425b0bb35..7392c746dfad96 100644 --- a/Lib/_pyrepl/reader.py +++ b/Lib/_pyrepl/reader.py @@ -104,6 +104,7 @@ def make_default_commands() -> dict[CommandName, CommandClass]: (r"\C-u", "unix-line-discard"), (r"\C-w", "unix-word-rubout"), (r"\C-x\C-u", "upcase-region"), + (r"\C-x\C-e", "open-input-in-editor"), (r"\C-y", "yank"), *(() if sys.platform == "win32" else ((r"\C-z", "suspend"), )), (r"\M-b", "backward-word"), diff --git a/Misc/NEWS.d/next/Library/2026-05-05-10-12-13.gh-issue-149392.vsURNh.rst b/Misc/NEWS.d/next/Library/2026-05-05-10-12-13.gh-issue-149392.vsURNh.rst new file mode 100644 index 00000000000000..518e486d8f2d3e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-05-10-12-13.gh-issue-149392.vsURNh.rst @@ -0,0 +1 @@ +Add "Open Input in Editor" support to :mod:`!_pyrepl`.