diff --git a/Cargo.lock b/Cargo.lock index f4047e1c..87342173 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,6 +153,16 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clap_mangen" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb258c6232b4d728d13d6072656627924c16707aae6267cd5a1ea05abff9a25c" +dependencies = [ + "clap", + "roff", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -935,6 +945,7 @@ dependencies = [ "assert_cmd", "assert_fs", "clap", + "clap_mangen", "enum_dispatch", "flate2", "git-version", @@ -1244,6 +1255,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "roff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" + [[package]] name = "rustc-hash" version = "1.1.0" diff --git a/pineappl_cli/Cargo.toml b/pineappl_cli/Cargo.toml index 97223d01..efdecec9 100644 --- a/pineappl_cli/Cargo.toml +++ b/pineappl_cli/Cargo.toml @@ -15,6 +15,7 @@ version.workspace = true [dependencies] anyhow = "1.0.48" clap = { features = ["deprecated", "derive"], version = "4.0.32" } +clap_mangen = "0.2.7" enum_dispatch = "0.3.7" flate2 = { optional = true, version = "1.0.22" } git-version = "0.3.5" diff --git a/pineappl_cli/src/help.rs b/pineappl_cli/src/help.rs new file mode 100644 index 00000000..e5dbcf8e --- /dev/null +++ b/pineappl_cli/src/help.rs @@ -0,0 +1,49 @@ +use super::helpers::{GlobalConfiguration, Subcommand}; +use anyhow::Result; +use clap::{CommandFactory, Parser}; +use clap_mangen::Man; +use std::io::Write; +use std::process::{Command, ExitCode, Stdio}; + +/// Display a manpage for selected subcommands. +#[derive(Parser)] +pub struct Opts { + /// Name of the (chain of) subcommand(s) to read the manpage of. + subcommand: Vec, +} + +impl Subcommand for Opts { + fn run(&self, _: &GlobalConfiguration) -> Result { + let cmd = crate::Opts::command(); + let subcmd = if self.subcommand.is_empty() { + cmd + } else { + let mut iter = self.subcommand.iter(); + let mut cmd = cmd; + while let Some(s) = iter.next() { + // TODO: if `unwrap` fails the arguments to `help` are wrong + cmd = cmd.find_subcommand(s).unwrap().clone(); + } + cmd + }; + let man = Man::new(subcmd); + let mut buffer = Vec::new(); + + man.render(&mut buffer)?; + + // TODO: check remaining `unwrap`s + + // TODO: is this the best way? What do we do when `man` isn't available (Windows, ...)? + let mut child = Command::new("man") + .args(["-l", "-"]) + .stdin(Stdio::piped()) + .stdout(Stdio::inherit()) + .spawn() + .unwrap(); + + child.stdin.take().unwrap().write_all(&buffer).unwrap(); + child.wait().unwrap(); + + Ok(ExitCode::SUCCESS) + } +} diff --git a/pineappl_cli/src/main.rs b/pineappl_cli/src/main.rs index 08984d8b..860d6cf8 100644 --- a/pineappl_cli/src/main.rs +++ b/pineappl_cli/src/main.rs @@ -6,6 +6,7 @@ mod convolute; mod delete; mod diff; mod evolve; +mod help; mod helpers; mod import; mod info; @@ -59,6 +60,7 @@ enum SubcommandEnum { Delete(delete::Opts), Diff(diff::Opts), Evolve(evolve::Opts), + Help(help::Opts), Import(import::Opts), Info(info::Opts), Merge(merge::Opts),