Skip to content

Commit 377808b

Browse files
committed
Support 'editting in external editor'
1 parent efcac6f commit 377808b

2 files changed

Lines changed: 46 additions & 0 deletions

File tree

Lib/_pyrepl/commands.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
import time
2525
from typing import TYPE_CHECKING
2626

27+
lazy import subprocess
28+
lazy import tempfile
29+
lazy from pathlib import Path
30+
2731
# Categories of actions:
2832
# killing
2933
# yanking
@@ -519,3 +523,44 @@ def do(self) -> None:
519523
s=time.time() - start,
520524
)
521525
self.reader.insert(data.replace(done, ""))
526+
527+
528+
class edit_in_editor(EditCommand):
529+
def do(self) -> None:
530+
r = self.reader
531+
532+
editor = os.environ.get("VISUAL") or os.environ.get("EDITOR")
533+
if not editor:
534+
editor = "vi" if os.name != "nt" else "notepad"
535+
536+
with tempfile.NamedTemporaryFile(mode="w+", suffix=".py", delete=False, encoding="utf-8") as f:
537+
tmp_path = Path(f.name)
538+
f.write("".join(r.buffer))
539+
f.flush()
540+
541+
try:
542+
with r.suspend():
543+
cmd = editor.split() + [str(tmp_path)]
544+
try:
545+
subprocess.call(cmd)
546+
except FileNotFoundError:
547+
r.error(f"Editor not found: {editor}")
548+
return
549+
except Exception as e:
550+
r.error(f"Failed to run editor: {e}")
551+
return
552+
553+
try:
554+
new_text = tmp_path.read_text(encoding="utf-8").rstrip("\n")
555+
r.buffer.clear()
556+
r.buffer.extend(new_text)
557+
r.pos = len(r.buffer)
558+
r.invalidate_full()
559+
r.console.repaint()
560+
except Exception as e:
561+
r.error(f"Failed to read edited file: {e}")
562+
finally:
563+
try:
564+
tmp_path.unlink(missing_ok=True)
565+
except Exception:
566+
pass

Lib/_pyrepl/reader.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ def make_default_commands() -> dict[CommandName, CommandClass]:
104104
(r"\C-u", "unix-line-discard"),
105105
(r"\C-w", "unix-word-rubout"),
106106
(r"\C-x\C-u", "upcase-region"),
107+
(r"\C-x\C-e", "edit-in-editor"),
107108
(r"\C-y", "yank"),
108109
*(() if sys.platform == "win32" else ((r"\C-z", "suspend"), )),
109110
(r"\M-b", "backward-word"),

0 commit comments

Comments
 (0)