From f227831febbc76f11aa748611de6099dc2b1e84d Mon Sep 17 00:00:00 2001 From: rob Date: Fri, 5 Dec 2025 02:04:42 -0400 Subject: [PATCH] Add $EDITOR button to open code in external editor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When editing a code step, users can now click the "$EDITOR" button to open the current code in their preferred external editor: - Uses $EDITOR environment variable (falls back to $VISUAL, then nano) - Creates a temp .py file with current code - Suspends urwid UI while editor runs - Imports edited code back when editor closes - Shows success/error status in the dialog This allows using vim, nano, VS Code, or any editor for complex code editing while still using the SmartTools UI for workflow. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/smarttools/ui_urwid.py | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/smarttools/ui_urwid.py b/src/smarttools/ui_urwid.py index 84cb043..8138628 100644 --- a/src/smarttools/ui_urwid.py +++ b/src/smarttools/ui_urwid.py @@ -1788,7 +1788,54 @@ Return ONLY the Python code, no explanations or markdown fencing.""" def on_cancel(_): self.close_overlay() + def on_external_edit(_): + """Open code in external editor ($EDITOR).""" + import os + import subprocess + import tempfile + + current_code = code_edit.edit_text + + # Stop the urwid loop temporarily + if self.loop: + self.loop.stop() + + try: + # Create temp file with current code + with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f: + f.write(current_code) + temp_path = f.name + + # Get editor from environment + editor = os.environ.get('EDITOR', os.environ.get('VISUAL', 'nano')) + + # Run editor + subprocess.run([editor, temp_path], check=True) + + # Read back the edited code + with open(temp_path, 'r') as f: + new_code = f.read() + + # Update the code editor + code_edit.set_edit_text(new_code) + status_text.set_text(('success', f"Code updated from {editor}")) + + # Clean up temp file + os.unlink(temp_path) + + except subprocess.CalledProcessError: + status_text.set_text(('error', "Editor exited with error")) + except FileNotFoundError: + status_text.set_text(('error', f"Editor '{editor}' not found")) + except Exception as e: + status_text.set_text(('error', f"Edit error: {e}")) + finally: + # Restart the urwid loop + if self.loop: + self.loop.start() + load_btn = Button3DCompact("Load", on_load) + edit_btn = Button3DCompact("$EDITOR", on_external_edit) # Code editor in a box - use ListBox for proper focus handling and scrolling # Wrap in DOSScrollBar for DOS-style scrollbar with arrow buttons @@ -1814,6 +1861,8 @@ Return ONLY the Python code, no explanations or markdown fencing.""" ('weight', 1, urwid.AttrMap(file_edit, 'edit', 'edit_focus')), ('pack', urwid.Text(" ")), ('pack', load_btn), + ('pack', urwid.Text(" ")), + ('pack', edit_btn), ])), ('pack', status_text), ('weight', 1, main_columns),