diff --git a/src/commands/open/hook_ctx.rs b/src/commands/open/hook_ctx.rs index 5fae932..f42782b 100644 --- a/src/commands/open/hook_ctx.rs +++ b/src/commands/open/hook_ctx.rs @@ -1,7 +1,9 @@ +use anyhow::Result; use worktree_io::{ config::Config, - hooks::HookContext, + hooks::{run_hook, HookContext}, issue::IssueRef, + opener, repo_hooks::{combined_script, RepoConfig}, }; @@ -69,3 +71,30 @@ pub(super) fn build_hook_context(issue: &IssueRef, worktree_path: &std::path::Pa worktree_path: worktree_path.to_string_lossy().into_owned(), } } + +pub(super) fn launch_editor( + workspace: &std::path::Path, + cmd: Option<&str>, + post_hook: Option<&str>, + background: bool, + ctx: &HookContext, +) -> Result<()> { + match (cmd, post_hook) { + (Some(c), Some(s)) => { + let rendered = ctx.render(s); + if !opener::open_with_hook(workspace, c, &rendered, background)? { + eprintln!("Running post:open hook…"); + run_hook(s, ctx)?; + } + } + (Some(c), None) => { + opener::open_editor_or_terminal(workspace, c, background)?; + } + (None, Some(s)) => { + eprintln!("Running post:open hook…"); + run_hook(s, ctx)?; + } + (None, None) => {} + } + Ok(()) +} diff --git a/src/commands/open/mod.rs b/src/commands/open/mod.rs index 021462e..c336be7 100644 --- a/src/commands/open/mod.rs +++ b/src/commands/open/mod.rs @@ -7,15 +7,19 @@ use worktree_io::{ config::Config, hooks::run_hook, issue::{DeepLinkOptions, IssueRef}, - opener, repo_hooks_scaffold::scaffold_if_missing, ttl::{self, WorkspaceRegistry}, workspace::Workspace, }; -use hook_ctx::{build_hook_context, effective_hooks}; +use hook_ctx::{build_hook_context, effective_hooks, launch_editor}; -pub fn cmd_open(issue_ref: Option<&str>, force_editor: bool, no_hooks: bool) -> Result<()> { +pub fn cmd_open( + issue_ref: Option<&str>, + force_editor: bool, + no_hooks: bool, + headless: bool, +) -> Result<()> { let (issue, deep_link_opts) = match issue_ref { Some(r) => IssueRef::parse_with_options(r)?, None => (IssueRef::from_current_repo()?, DeepLinkOptions::default()), @@ -63,6 +67,13 @@ pub fn cmd_open(issue_ref: Option<&str>, force_editor: bool, no_hooks: bool) -> run_hook(script, &hook_ctx)?; } + if headless { + if let Some(script) = &effective_post { + eprintln!("Running post:open hook…"); + run_hook(script, &hook_ctx)?; + } + return Ok(()); + } let editor_cmd: Option = if let Some(editor_name) = deep_link_opts.editor { Some(editor::resolve_editor_command(&editor_name)) } else if force_editor || config.open.editor { @@ -73,25 +84,13 @@ pub fn cmd_open(issue_ref: Option<&str>, force_editor: bool, no_hooks: bool) -> } else { None }; - - match (editor_cmd.as_deref(), effective_post.as_deref()) { - (Some(cmd), Some(script)) => { - let rendered = hook_ctx.render(script); - if !opener::open_with_hook(&workspace.path, cmd, &rendered, config.editor.background)? { - eprintln!("Running post:open hook…"); - run_hook(script, &hook_ctx)?; - } - } - (Some(cmd), None) => { - opener::open_editor_or_terminal(&workspace.path, cmd, config.editor.background)?; - } - (None, Some(script)) => { - eprintln!("Running post:open hook…"); - run_hook(script, &hook_ctx)?; - } - (None, None) => {} - } - + launch_editor( + &workspace.path, + editor_cmd.as_deref(), + effective_post.as_deref(), + config.editor.background, + &hook_ctx, + )?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index 9a80bb3..1fcdc29 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ #![allow(missing_docs)] // binary crate; public API lives in the library use anyhow::Result; use clap::{Parser, Subcommand}; - mod commands; use commands::config::{cmd_config, ConfigAction}; use commands::list::cmd_list; @@ -12,7 +11,6 @@ use commands::prune::cmd_prune; use commands::restore::cmd_restore; use commands::scheme::{cmd_scheme, SchemeAction}; use commands::setup::cmd_setup; - #[derive(Parser)] #[command( name = "worktree", @@ -23,7 +21,6 @@ struct Cli { #[command(subcommand)] command: Commands, } - #[derive(Subcommand)] enum Commands { /// Parse an issue reference, create a worktree, and open it @@ -37,6 +34,9 @@ enum Commands { /// Skip pre/post-open hooks #[arg(long)] no_hooks: bool, + /// Skip opening editor/terminal (hooks still run); useful for programmatic invocation + #[arg(long)] + headless: bool, }, /// Open multiple repos as a unified workspace under ~/workspaces// #[command(name = "open-multi")] @@ -85,7 +85,8 @@ fn main() -> Result<()> { issue_ref, editor, no_hooks, - } => cmd_open(issue_ref.as_deref(), editor, no_hooks)?, + headless, + } => cmd_open(issue_ref.as_deref(), editor, no_hooks, headless)?, Commands::OpenMulti { refs, no_hooks } => cmd_open_multi(&refs, no_hooks)?, Commands::Config { action } => cmd_config(action)?, Commands::List { json } => cmd_list(json)?,