use anyhow::{Context, Result};
use std::io::{IsTerminal, Write};
use std::process::{Command, Stdio};
const CHANGELOG: &str = include_str!("../../CHANGELOG.md");
pub fn run() -> Result<()> {
if !std::io::stdout().is_terminal() {
print!("{}", CHANGELOG);
return Ok(());
}
let candidates: Vec<Vec<String>> = pager_candidates();
for argv in &candidates {
if let Some((cmd, args)) = argv.split_first() {
if try_pipe_to_pager(cmd, args, CHANGELOG).is_ok() {
return Ok(());
}
}
}
print!("{}", CHANGELOG);
Ok(())
}
fn pager_candidates() -> Vec<Vec<String>> {
let mut out: Vec<Vec<String>> = Vec::new();
if let Ok(pager) = std::env::var("PAGER") {
let parts: Vec<String> = pager.split_whitespace().map(|s| s.to_string()).collect();
if !parts.is_empty() {
out.push(parts);
}
}
out.push(vec!["less".into(), "-RFX".into()]);
out.push(vec!["more".into()]);
out
}
fn try_pipe_to_pager(cmd: &str, args: &[String], content: &str) -> Result<()> {
let mut child = Command::new(cmd)
.args(args)
.stdin(Stdio::piped())
.spawn()
.with_context(|| format!("failed to spawn pager `{}`", cmd))?;
if let Some(mut stdin) = child.stdin.take() {
let _ = stdin.write_all(content.as_bytes());
}
let status = child.wait().context("pager did not exit cleanly")?;
if !status.success() {
anyhow::bail!("pager `{}` exited with {}", cmd, status);
}
Ok(())
}