Skip to main content

radicle_cli/
pager.rs

1use std::io;
2use std::process::{Command, Stdio};
3
4use radicle_term::element;
5use radicle_term::{Constraint, Element};
6
7use crate::terminal;
8
9/// Output the given element through a pager, if necessary.
10/// If it fits within the screen, don't run it through a pager.
11pub fn run(elem: impl Element) -> io::Result<()> {
12    let Some(constraint) = Constraint::from_env() else {
13        return elem.write(Constraint::UNBOUNDED);
14    };
15    let Some(rows) = terminal::rows() else {
16        return elem.write(Constraint::UNBOUNDED);
17    };
18    if elem.size(Constraint::UNBOUNDED).rows <= rows {
19        return elem.write(Constraint::UNBOUNDED);
20    }
21    let Some(pager) = radicle::profile::env::pager() else {
22        return elem.write(Constraint::UNBOUNDED);
23    };
24
25    #[cfg(unix)]
26    let Some(parts) = shlex::split(&pager) else {
27        return elem.write(Constraint::UNBOUNDED);
28    };
29    #[cfg(windows)]
30    let parts = winsplit::split(&pager);
31
32    let Some((program, args)) = parts.split_first() else {
33        return elem.write(Constraint::UNBOUNDED);
34    };
35
36    let mut child = Command::new(program)
37        .stdin(Stdio::piped())
38        .stdout(Stdio::inherit())
39        .stderr(Stdio::inherit())
40        .args(args)
41        .spawn()?;
42
43    let writer = child.stdin.as_mut().unwrap();
44    let result = element::write_to(&elem, writer, constraint);
45
46    child.wait()?;
47
48    match result {
49        // This error is expected when the pager is exited.
50        Err(e) if e.kind() == io::ErrorKind::BrokenPipe => {}
51        Err(e) => return Err(e),
52        Ok(_) => {}
53    }
54
55    Ok(())
56}