use {
crate::*,
anyhow::{
Result,
bail,
},
clap::{
CommandFactory,
Parser,
},
clap_complete::ArgValueCandidates,
termimad::ansi,
};
static INTRO: &str = "
**bacon** watches your project and runs jobs in background.
Use shortcuts to:
* switch job: *t* for `test`, *c* for `clippy`, *d* to open rust doc, etc.
* toggle display: *s* for summary, *w* for wrapped lines, etc.
* search: */*
* see all shortcuts: *?*
Complete documentation at https://dystroy.org/bacon
";
#[derive(Debug, Parser)]
#[command(
author,
about,
version,
disable_version_flag = true,
disable_help_flag = true
)]
pub struct Args {
#[arg(long)]
pub help: bool,
#[arg(long)]
pub version: bool,
#[clap(long)]
pub prefs: bool,
#[clap(long)]
pub headless: bool,
#[clap(short = 's', long)]
pub summary: bool,
#[clap(short = 'S', long)]
pub no_summary: bool,
#[clap(short = 'w', long)]
pub wrap: bool,
#[clap(short = 'W', long)]
pub no_wrap: bool,
#[clap(long)]
pub reverse: bool,
#[clap(long)]
pub no_reverse: bool,
#[clap(long)]
pub help_line: bool,
#[clap(long)]
pub no_help_line: bool,
#[clap(short = 'l', long)]
pub list_jobs: bool,
#[clap(long, hide = true)]
pub completion_list_jobs: bool,
#[clap(long)]
pub offline: bool,
#[clap(long)]
pub init: bool,
#[cfg(unix)]
#[clap(long)]
pub listen: bool,
#[cfg(unix)]
#[clap(long)]
pub no_listen: bool,
#[cfg(unix)]
#[clap(long)]
pub send: Option<String>,
#[clap(short = 'j', long, value_name = "job", add = ArgValueCandidates::new(crate::cli::completions::list_jobs))]
pub job: Option<ConcreteJobRef>,
#[clap(long)]
pub no_default_features: bool,
#[clap(long, value_name = "features")]
pub features: Option<String>,
#[clap(long)]
pub all_features: bool,
#[clap(short = 'e', long)]
pub export_locations: bool,
#[clap(short = 'E', long)]
pub no_export_locations: bool,
#[clap(long, value_name = "watch", value_hint = clap::ValueHint::FilePath)]
pub watch: Option<String>,
#[clap(long, value_name = "project", value_hint = clap::ValueHint::DirPath)]
pub project: Option<String>,
#[clap(long)]
pub config_toml: Option<String>,
#[clap(long, hide = true)]
pub generate_config_schema: bool,
#[clap(add = ArgValueCandidates::new(crate::cli::completions::list_jobs))]
pub args: Vec<String>,
#[clap(last = true)]
pub additional_job_args: Vec<String>,
}
impl Args {
pub fn fix(&mut self) -> Result<()> {
let mut args = self.args.drain(..);
match (
args.next(),
args.next(),
self.job.is_none(),
self.project.is_none(),
) {
(Some(a), b, true, true) => {
if a.contains('.') || a.contains('/') {
self.project = Some(a);
self.job = b.map(|b| b.as_str().into());
} else {
self.job = Some(a.as_str().into());
self.project = b;
}
}
(Some(_), Some(_), _, _) => {
bail!("Too many arguments");
}
(Some(a), None, true, false) => {
self.job = Some(a.as_str().into());
}
(Some(a), None, false, true) => {
self.project = Some(a);
}
(Some(a), None, false, false) => {
bail!("Unexpected argument {a:?}");
}
_ => {}
}
Ok(())
}
pub fn print_help(&self) {
let mut printer = clap_help::Printer::new(Args::command())
.with("introduction", INTRO)
.with("options", clap_help::TEMPLATE_OPTIONS_MERGED_VALUE)
.without("author");
let skin = printer.skin_mut();
skin.headers[0].compound_style.set_fg(ansi(204));
skin.bold.set_fg(ansi(204));
skin.italic = termimad::CompoundStyle::with_fg(ansi(204));
printer.template_keys_mut().push("examples");
printer.set_template("examples", EXAMPLES_TEMPLATE);
for (i, example) in EXAMPLES.iter().enumerate() {
printer
.expander_mut()
.sub("examples")
.set("example-number", i + 1)
.set("example-title", example.title)
.set("example-cmd", example.cmd);
}
printer.print_help();
}
}