use std::env;
use std::io::Write;
use std::process::Command;
use anyhow::{Context, Result};
pub fn open(text: &str, open_with: Option<&str>) -> Result<()> {
let viewer_str = match open_with {
Some(program) => program.to_string(),
None => {
if let Ok(editor) = env::var("EDITOR") {
editor
} else if let Ok(pager) = env::var("PAGER") {
pager
} else {
return Ok(());
}
}
};
let (program, extra_args) = split_command(&viewer_str)
.with_context(|| format!("Empty viewer command: {:?}", viewer_str))?;
let mut temp_file = tempfile::NamedTempFile::new()?;
temp_file.write_all(text.as_bytes())?;
temp_file.flush()?;
let status = Command::new(&program)
.args(&extra_args)
.arg(temp_file.path())
.status()
.with_context(|| format!("Failed to start viewer: {}", program))?;
if !status.success() {
anyhow::bail!("Viewer exited with non-zero status");
}
Ok(())
}
fn split_command(s: &str) -> Option<(String, Vec<String>)> {
let mut parts = s.split_whitespace().map(String::from);
let program = parts.next()?;
Some((program, parts.collect()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn split_command_basic() {
assert_eq!(split_command("vim"), Some(("vim".to_string(), vec![])));
}
#[test]
fn split_command_with_args() {
assert_eq!(
split_command("code -"),
Some(("code".to_string(), vec!["-".to_string()]))
);
assert_eq!(
split_command("nvim -R"),
Some(("nvim".to_string(), vec!["-R".to_string()]))
);
}
#[test]
fn split_command_empty() {
assert_eq!(split_command(""), None);
assert_eq!(split_command(" "), None);
}
}