use crate::cli_doc::ArgSpec;
use crate::encoding::Encoding;
#[derive(Default, Clone)]
pub struct CliExtensions {
pub encoding: Option<Encoding>,
gif_blocks: Option<bool>,
}
pub const HELP: &str = " --gif-mode M With --gif: ascii (default) or blocks (half-block pixels).\n Blocks fall back to ASCII without color or when piped.\n --encoding E Explicit text encoding: utf-8, utf-16 (BOM required),\n utf-16le or utf-16be. Strict; files, stdin and URLs only.";
pub fn arg_specs() -> Vec<ArgSpec> {
vec![
ArgSpec::option("gif-mode")
.value_name("M")
.choices(["ascii", "blocks"])
.default_value("ascii")
.help("With --gif: ascii or blocks (half-block pixels). Blocks fall back to ASCII without color or when piped."),
ArgSpec::option("encoding")
.value_name("E")
.choices(["utf-8", "utf-16", "utf-16le", "utf-16be"])
.help("Explicit text encoding: utf-8, utf-16 (BOM required), utf-16le or utf-16be. Strict; files, stdin and URLs only."),
]
}
impl CliExtensions {
pub fn parse_option<'a>(
&mut self,
arg: &str,
rest: &mut impl Iterator<Item = &'a String>,
) -> Result<bool, String> {
match arg {
"--gif-mode" => {
self.gif_blocks = Some(match rest.next().map(String::as_str) {
Some("ascii") => false,
Some("blocks") => true,
_ => return Err("--gif-mode requires ascii or blocks".into()),
})
}
"--encoding" => {
self.encoding = Some(
rest.next()
.ok_or("--encoding requires an encoding name")?
.parse()?,
)
}
_ => return Ok(false),
}
Ok(true)
}
pub fn validate(&self, gif: bool, reads_text: bool) -> Result<(), String> {
if self.gif_blocks.is_some() && !gif {
return Err("--gif-mode only has an effect with --gif".into());
}
if self.encoding.is_some() && !reads_text {
return Err("--encoding requires file, stdin or URL text input".into());
}
Ok(())
}
pub fn gif_blocks(&self) -> bool {
self.gif_blocks.unwrap_or(false)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn arg_specs_match_the_options_parse_option_consumes() {
for spec in arg_specs() {
let long = spec.primary();
assert!(HELP.contains(&long), "{long} missing from HELP");
let value = spec.choice_list()[0].value.clone();
let rest = [value];
let mut iter = rest.iter();
assert_eq!(
CliExtensions::default().parse_option(&long, &mut iter),
Ok(true),
"{long}"
);
}
}
}