use anyhow::{Context, Result};
use crossterm::execute;
use crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
};
use std::io::stdout;
use std::path::Path;
use std::process::{Command, Stdio};
pub fn editor_program() -> String {
crate::runtime::platform::default_editor()
}
pub fn open_editor(path: &Path) -> Result<()> {
let program = editor_program();
let mut tokens = program.split_whitespace();
let editor_bin = tokens.next().unwrap_or(program.as_str());
let editor_args: Vec<&str> = tokens.collect();
let editor_exe = crate::runtime::platform::find_executable(editor_bin)
.unwrap_or_else(|| std::path::PathBuf::from(editor_bin));
disable_raw_mode().ok();
execute!(stdout(), LeaveAlternateScreen).ok();
let status = Command::new(&editor_exe)
.args(&editor_args)
.arg(path)
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status();
let _ = enable_raw_mode();
let _ = execute!(stdout(), EnterAlternateScreen);
let status = status.with_context(|| format!("executando editor '{program}'"))?;
if !status.success() {
anyhow::bail!("editor '{program}' encerrou com código {:?}", status.code());
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fallback_is_platform_aware_when_unset() {
let _env = crate::runtime::platform::lock_env();
let saved_visual = std::env::var("VISUAL").ok();
let saved_editor = std::env::var("EDITOR").ok();
std::env::remove_var("VISUAL");
std::env::remove_var("EDITOR");
assert_eq!(editor_program(), crate::runtime::platform::default_editor());
match saved_visual {
Some(v) => std::env::set_var("VISUAL", v),
None => std::env::remove_var("VISUAL"),
}
match saved_editor {
Some(v) => std::env::set_var("EDITOR", v),
None => std::env::remove_var("EDITOR"),
}
}
#[test]
fn uses_editor_env_when_set() {
let _env = crate::runtime::platform::lock_env();
let saved_visual = std::env::var("VISUAL").ok();
let saved_editor = std::env::var("EDITOR").ok();
std::env::remove_var("VISUAL");
std::env::set_var("EDITOR", "nano");
assert_eq!(editor_program(), "nano");
match saved_visual {
Some(v) => std::env::set_var("VISUAL", v),
None => std::env::remove_var("VISUAL"),
}
match saved_editor {
Some(v) => std::env::set_var("EDITOR", v),
None => std::env::remove_var("EDITOR"),
}
}
}