Skip to content

Commit b79201c

Browse files
committed
Add support for external pagers
If stdout is a TTY, the output of the show command will be sent to a pager.
1 parent f25b4b0 commit b79201c

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use gumdrop::Options;
33
mod hubapi;
44
mod langext;
55
mod options;
6+
mod pager;
67
mod search;
78
mod show;
89
mod tags;

src/pager.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//! Run an external program as a pager (like "less")
2+
3+
use std::env;
4+
use std::process::{Command, Stdio};
5+
6+
pub const PAGER_ENV: &str = "HDC_PAGER";
7+
8+
const DEFAULT_PAGER: &str = if cfg!(windows) { "more" } else { "pager -F" };
9+
10+
pub fn command(repository: Option<&str>) -> Option<Command> {
11+
if !atty::is(atty::Stream::Stdout) {
12+
return None;
13+
}
14+
15+
let pager_var = env::var(PAGER_ENV);
16+
let mut pager_args = pager_var
17+
.as_deref()
18+
.unwrap_or(DEFAULT_PAGER)
19+
.split_whitespace();
20+
21+
let mut cmd = Command::new(pager_args.next()?);
22+
23+
for arg in pager_args {
24+
cmd.arg(arg);
25+
}
26+
27+
cmd.stdin(Stdio::piped());
28+
cmd.env("HDCQUERY_VERSION", env!("CARGO_PKG_VERSION"));
29+
repository.map(|r| cmd.env("HDCQUERY_REPOSITORY", r));
30+
31+
Some(cmd)
32+
}

src/search.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ fn search_apache_repository() {
224224
use std::process::Command;
225225

226226
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
227+
cmd.env(crate::pager::PAGER_ENV, "cat");
227228
cmd.args(&["search", "apache"]);
228229
let mut cmd = spawn_command(cmd, Some(60_000)).unwrap();
229230

src/show.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
//! Implementation of the 'show' command
2+
//!
3+
//! The pager will receive the following environment variables:
4+
//!
5+
//! * `HDCQUERY_REPOSITORY`: name of the repository, like `"library/rust"`.
6+
//! * `HDCQUERY_VERSION`: version of hdcquery.
27
38
use crate::hubapi::Repository;
49
use crate::langext::DurationExt;
@@ -31,18 +36,42 @@ pub async fn show_repository_by_slug(slug: &str) -> anyhow::Result<()> {
3136
}
3237

3338
pub async fn show_repository(repository: &Repository) -> anyhow::Result<()> {
39+
let pager_cmd;
40+
let mut pager_stdin;
41+
let mut io_stdout;
42+
43+
let output: &mut dyn std::io::Write;
44+
3445
macro_rules! option_field {
3546
($field:ident, $label:literal) => {
3647
option_field!($field, $label, $field)
3748
};
3849

3950
($field:ident, $label:literal, $render:expr) => {
4051
if let Some($field) = &repository.$field {
41-
println!(concat!($label, ": {}"), $render)
52+
writeln!(output, concat!($label, ": {}"), $render)?
4253
}
4354
};
4455
}
4556

57+
let slug = match (&repository.namespace, &repository.name) {
58+
(Some(ns), Some(n)) => Some(format!("{}/{}", ns, n)),
59+
_ => None,
60+
};
61+
62+
if let Some(mut cmd) = crate::pager::command(slug.as_deref()) {
63+
let mut child = cmd.spawn()?;
64+
pager_stdin = child.stdin.take();
65+
pager_cmd = Some(child);
66+
67+
output = pager_stdin.as_mut().expect("stdin expected for pager");
68+
} else {
69+
pager_cmd = None;
70+
pager_stdin = None;
71+
io_stdout = std::io::stdout();
72+
output = &mut io_stdout;
73+
}
74+
4675
option_field!(namespace, "Namespace");
4776
option_field!(name, "Name");
4877
option_field!(description, "Description");
@@ -56,17 +85,22 @@ pub async fn show_repository(repository: &Repository) -> anyhow::Result<()> {
5685
);
5786

5887
if let Some(last_updated) = &repository.last_updated {
59-
println!(
88+
writeln!(
89+
output,
6090
"Last updated: {} ({})",
6191
last_updated.format("%F %R %Z"),
6292
last_updated.to_human()
63-
);
93+
)?;
6494
}
6595

6696
if let Some(full_description) = &repository.full_description {
67-
println!("\n----\n\n{}\n\n----", full_description);
97+
writeln!(output, "\n----\n\n{}\n\n----", full_description)?;
6898
}
6999

100+
// Close the pager's input
101+
drop(pager_stdin);
102+
let _ = pager_cmd.map(|mut c| c.wait());
103+
70104
Ok(())
71105
}
72106

0 commit comments

Comments
 (0)