Skip to content

Commit

Permalink
Encapsulate pager process code
Browse files Browse the repository at this point in the history
  • Loading branch information
jpikl committed Apr 20, 2024
1 parent f9dd188 commit 51d38ab
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 46 deletions.
22 changes: 3 additions & 19 deletions src/examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::colors::Colorizer;
use crate::colors::GREEN;
use crate::colors::RESET;
use crate::colors::YELLOW;
use crate::pager;
use crate::pager::Pager;
use anstream::adapter::strip_str;
use anstream::stdout;
use anyhow::Result;
Expand All @@ -13,8 +13,6 @@ use clap::ArgMatches;
use clap::Command;
use std::io;
use std::io::Write;
use std::panic::resume_unwind;
use std::thread;
use terminal_size::terminal_size;
use terminal_size::Width;
use unicode_width::UnicodeWidthStr;
Expand Down Expand Up @@ -75,22 +73,8 @@ pub fn is_arg_set(matches: &ArgMatches) -> bool {
}

pub fn print(command: &'static str, examples: &'static [Example]) -> Result<()> {
if let Some(mut pager) = pager::open()? {
let mut stdin = pager.take_stdin().expect("could not get pager stdin");

let thread = thread::spawn(move || {
write(&mut stdin.inner, command, examples).map_err(|err| {
stdin
.context
.apply(err)
.context("failed to write to child process stdin")
})
});

pager.wait()?;
thread.join().map_err(resume_unwind)??;

Ok(())
if let Some(mut pager) = Pager::detect() {
pager.open(|stdin| write(stdin, command, examples))
} else {
write(&mut stdout().lock(), command, examples)
}
Expand Down
75 changes: 48 additions & 27 deletions src/pager.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,62 @@
use crate::process::CommandEx;
use crate::process::Spawned;
use anstream::stream::IsTerminal;
use anyhow::Result;
use std::io::stdout;
use std::path::Path;
use std::process::Child;
use std::panic::resume_unwind;
use std::process::ChildStdin;
use std::process::Command;
use std::process::Stdio;
use std::thread;
use which::which;

pub fn open() -> Result<Option<Spawned<Child>>> {
if !stdout().is_terminal() {
return Ok(None);
}
pub struct Pager(Command);

// We could eventually do something more complex, such as parsing PAGER
// env variable like `bat` does https://github.com/sharkdp/bat/issues/158,
// but that would be an overkill for our use case.
if let Ok(path) = which("less") {
// F = Exit immediately if the text fits the entire screen.
// I = Ignore case when searching.
// r = Causes "raw" control characters to be displayed.
// X = Disables sending the termcap (in)itialization.
return spawn(&path, &["-FIrX"]);
}
impl Pager {
pub fn detect() -> Option<Pager> {
if !stdout().is_terminal() {
return None;
}

// We could eventually do something more complex, such as parsing PAGER
// env variable like `bat` does https://github.com/sharkdp/bat/issues/158,
// but that would be an overkill for our use case.

if let Ok(path) = which("less") {
let mut command = Command::new(path);
// F = Exit immediately if the text fits the entire screen.
// I = Ignore case when searching.
// r = Causes "raw" control characters to be displayed.
// X = Disables sending the termcap (de)itialization.
command.arg("-FIrX");
return Some(Pager(command));
}

if let Ok(path) = which("more") {
return Some(Pager(Command::new(path)));
}

if let Ok(path) = which("more") {
return spawn(&path, &[]);
None
}

Ok(None)
}
pub fn open(
&mut self,
callback: impl Fn(&mut ChildStdin) -> Result<()> + Send + 'static,
) -> Result<()> {
let mut pager = self.0.stdin(Stdio::piped()).spawn_with_context()?;
let mut stdin = pager.take_stdin().expect("could not get pager stdin");

let thread = thread::spawn(move || {
callback(&mut stdin.inner).map_err(|err| {
stdin
.context
.apply(err)
.context("failed to write to child process stdin")
})
});

fn spawn(path: &Path, args: &[&str]) -> Result<Option<Spawned<Child>>> {
Command::new(path)
.args(args)
.stdin(Stdio::piped())
.spawn_with_context()
.map(Some)
pager.wait()?;
thread.join().map_err(resume_unwind)??;

Ok(())
}
}

0 comments on commit 51d38ab

Please sign in to comment.