worktree_io/opener/
mod.rs1pub mod available_entries;
3mod editor;
4pub mod entries;
6mod is_available;
7mod shell;
8mod terminal;
9#[cfg(windows)]
10mod wt;
11
12pub use editor::resolve_editor_command;
13pub use shell::augmented_path;
14
15use anyhow::{Context, Result};
16use std::path::Path;
17
18#[cfg(target_os = "macos")]
20fn app_exists(name: &str) -> bool {
21 std::path::Path::new(&format!("/Applications/{name}.app")).exists()
22 || std::path::Path::new(&format!("/System/Applications/{name}.app")).exists()
23}
24
25fn open_hook_in_auto_terminal(path: &Path, init_script: &str) -> Result<bool> {
27 #[cfg(windows)]
28 if which::which("wt").is_ok() && terminal::try_terminal_with_init(path, "wt", init_script)? {
29 return Ok(true);
30 }
31 if which::which("tmux").is_ok() && terminal::try_terminal_with_init(path, "tmux", init_script)?
32 {
33 return Ok(true);
34 }
35 #[cfg(target_os = "macos")]
36 {
37 let candidates: &[(&str, &str)] = &[
38 ("iTerm", "open -a iTerm ."),
39 ("Warp", "open -a Warp ."),
40 ("Ghostty", "open -a Ghostty ."),
41 ("Terminal", "open -a Terminal ."),
42 ];
43 for &(app, cmd) in candidates {
44 if app_exists(app) && terminal::try_terminal_with_init(path, cmd, init_script)? {
46 return Ok(true);
47 }
48 }
50 }
51 Ok(false)
52}
53
54pub fn open_with_hook(path: &Path, cmd: &str, init: &str, background: bool) -> Result<bool> {
60 if terminal::try_terminal_with_init(path, cmd, init)? {
61 return Ok(true);
62 }
63 open_in_editor(path, cmd, background)?;
64 open_hook_in_auto_terminal(path, init)
65}
66
67pub fn open_in_editor(path: &Path, command: &str, background: bool) -> Result<()> {
74 let path_str = path
75 .to_str()
76 .context("Workspace path contains non-UTF-8 characters")?;
77 let cmd_str = if command.contains(" . ") || command.ends_with(" .") || command == "." {
78 command.replacen(" .", &format!(" {path_str}"), 1)
79 } else {
80 format!("{command} {path_str}")
81 };
82
83 shell::run_shell_command(&cmd_str, background)
84 .with_context(|| format!("Failed to open editor with command: {cmd_str}"))
85}
86
87pub fn open_editor_or_terminal(path: &Path, cmd: &str, background: bool) -> Result<()> {
92 if !terminal::try_terminal_with_init(path, cmd, "")? {
93 open_in_editor(path, cmd, background)?;
94 }
95 Ok(())
96}
97
98#[cfg(test)]
99#[path = "opener_tests.rs"]
100mod tests;