1use crate::repo::GitRepo;
16
17use anyhow::Context as _;
18use crossterm::{execute, terminal};
19
20fn resolve_editor(repo: &impl GitRepo) -> String {
29 if let Ok(e) = std::env::var("GIT_EDITOR") {
30 return e.trim().to_string();
31 }
32
33 if let Some(e) = repo.get_config_string("core.editor") {
34 return e.trim().to_string();
35 }
36
37 for var in ["VISUAL", "EDITOR"] {
38 if let Ok(e) = std::env::var(var) {
39 return e.trim().to_string();
40 }
41 }
42
43 "vi".to_string()
44}
45
46fn launch_editor(repo: &impl GitRepo, path: &std::path::Path) -> anyhow::Result<()> {
54 let editor_cmd = resolve_editor(repo);
55 let mut parts = editor_cmd.split_whitespace();
56 let prog = parts
57 .next()
58 .ok_or_else(|| anyhow::anyhow!("editor command is empty"))?;
59 let args: Vec<&str> = parts.collect();
60
61 terminal::disable_raw_mode().context("failed to disable raw mode")?;
63 execute!(std::io::stdout(), terminal::LeaveAlternateScreen)
64 .context("failed to leave alternate screen")?;
65
66 let status = std::process::Command::new(prog)
67 .args(&args)
68 .arg(path)
69 .status();
70
71 let _ = terminal::enable_raw_mode();
73 let _ = execute!(std::io::stdout(), terminal::EnterAlternateScreen);
74
75 let status = status.with_context(|| format!("failed to launch editor `{prog}`"))?;
76 if !status.success() {
77 anyhow::bail!("editor exited with {status}");
78 }
79 Ok(())
80}
81
82pub fn edit_message_in_editor(repo: &impl GitRepo, message: &str) -> anyhow::Result<String> {
84 use std::io::Write as _;
85
86 let mut tmpfile =
87 tempfile::NamedTempFile::new().context("failed to create temp file for commit message")?;
88 write!(tmpfile, "{message}").context("failed to write commit message to temp file")?;
89
90 launch_editor(repo, tmpfile.path())?;
91
92 let edited =
93 std::fs::read_to_string(tmpfile.path()).context("failed to read edited commit message")?;
94 Ok(edited.trim().to_string() + "\n")
95}
96
97pub fn open_file_in_editor(repo: &impl GitRepo, path: &std::path::Path) -> anyhow::Result<()> {
102 launch_editor(repo, path)
103}