From 673a59f5f7ce62a46908adb7c0a5e8b1f9324759 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 25 Jan 2026 22:59:03 +0000 Subject: [PATCH] Add Zed editor integration with --open-in-editor flag - Add editor config option to UIConfig (default: zed) - Create editor.py utility module for launching editors - Add --open-in-editor flag to generate command - Add --editor flag to override configured editor --- quantcoder/cli.py | 21 +++++++++++++-- quantcoder/config.py | 2 ++ quantcoder/editor.py | 62 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 quantcoder/editor.py diff --git a/quantcoder/cli.py b/quantcoder/cli.py index eb85878..622aeeb 100644 --- a/quantcoder/cli.py +++ b/quantcoder/cli.py @@ -186,12 +186,17 @@ def summarize(ctx, article_id): @main.command(name='generate') @click.argument('article_id', type=int) @click.option('--max-attempts', default=6, help='Maximum refinement attempts') +@click.option('--open-in-editor', is_flag=True, help='Open generated code in editor (default: Zed)') +@click.option('--editor', default=None, help='Editor to use (overrides config, e.g., zed, code, vim)') @click.pass_context -def generate_code(ctx, article_id, max_attempts): +def generate_code(ctx, article_id, max_attempts, open_in_editor, editor): """ Generate QuantConnect code from an article. - Example: quantcoder generate 1 + Example: + quantcoder generate 1 + quantcoder generate 1 --open-in-editor + quantcoder generate 1 --open-in-editor --editor code """ config = ctx.obj['config'] tool = GenerateCodeTool(config) @@ -224,6 +229,18 @@ def generate_code(ctx, article_id, max_attempts): title="Generated Code", border_style="green" )) + + # Open in editor if requested + if open_in_editor: + from .editor import open_in_editor as launch_editor, get_editor_display_name + editor_cmd = editor or config.ui.editor + editor_name = get_editor_display_name(editor_cmd) + code_path = result.data.get('path') + if code_path: + if launch_editor(code_path, editor_cmd): + console.print(f"[cyan]Opened in {editor_name}[/cyan]") + else: + console.print(f"[yellow]Could not open in {editor_name}. Is it installed?[/yellow]") else: console.print(f"[red]✗[/red] {result.error}") diff --git a/quantcoder/config.py b/quantcoder/config.py index 8ffde29..313d7a2 100644 --- a/quantcoder/config.py +++ b/quantcoder/config.py @@ -30,6 +30,7 @@ class UIConfig: theme: str = "monokai" auto_approve: bool = False show_token_usage: bool = True + editor: str = "zed" # Editor for --open-in-editor flag (zed, code, vim, etc.) @dataclass @@ -112,6 +113,7 @@ def to_dict(self) -> Dict[str, Any]: "theme": self.ui.theme, "auto_approve": self.ui.auto_approve, "show_token_usage": self.ui.show_token_usage, + "editor": self.ui.editor, }, "tools": { "enabled_tools": self.tools.enabled_tools, diff --git a/quantcoder/editor.py b/quantcoder/editor.py new file mode 100644 index 0000000..7401f04 --- /dev/null +++ b/quantcoder/editor.py @@ -0,0 +1,62 @@ +"""Editor integration utilities for QuantCoder CLI.""" + +import subprocess +import shutil +import logging +from pathlib import Path +from typing import Optional + +logger = logging.getLogger(__name__) + + +def open_in_editor(file_path: str, editor: str = "zed") -> bool: + """ + Open a file in the specified editor. + + Args: + file_path: Path to the file to open + editor: Editor command (zed, code, vim, nvim, etc.) + + Returns: + True if editor launched successfully, False otherwise + """ + path = Path(file_path) + + if not path.exists(): + logger.error(f"File not found: {file_path}") + return False + + # Check if editor is available + editor_path = shutil.which(editor) + if not editor_path: + logger.error(f"Editor '{editor}' not found in PATH") + return False + + try: + # Launch editor (non-blocking) + subprocess.Popen( + [editor, str(path)], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + start_new_session=True + ) + logger.info(f"Opened {file_path} in {editor}") + return True + except Exception as e: + logger.error(f"Failed to open editor: {e}") + return False + + +def get_editor_display_name(editor: str) -> str: + """Get a friendly display name for the editor.""" + editor_names = { + "zed": "Zed", + "code": "VS Code", + "vim": "Vim", + "nvim": "Neovim", + "nano": "Nano", + "subl": "Sublime Text", + "atom": "Atom", + "emacs": "Emacs", + } + return editor_names.get(editor, editor)