use clap::{Parser, ValueEnum};
use cryosnap_core::{
CjkRegion, FontSystemFallback, PngQuantPreset, PngStrip, RasterBackend, TitleAlign,
TitlePathStyle,
};
#[derive(Parser, Debug)]
#[command(
name = "cryosnap",
about = "Generate images of code and terminal output.",
version
)]
pub(crate) struct Args {
pub(crate) input: Option<String>,
#[arg(short, long)]
pub(crate) output: Option<std::path::PathBuf>,
#[arg(long, value_enum)]
pub(crate) format: Option<FormatArg>,
#[arg(short, long)]
pub(crate) config: Option<String>,
#[arg(short, long)]
pub(crate) interactive: bool,
#[arg(short = 'b', long)]
pub(crate) background: Option<String>,
#[arg(short = 'p', long)]
pub(crate) padding: Option<String>,
#[arg(short = 'm', long)]
pub(crate) margin: Option<String>,
#[arg(short = 'W', long)]
pub(crate) width: Option<f32>,
#[arg(short = 'H', long)]
pub(crate) height: Option<f32>,
#[arg(short = 't', long)]
pub(crate) theme: Option<String>,
#[arg(short = 'l', long)]
pub(crate) language: Option<String>,
#[arg(short = 'w', long)]
pub(crate) wrap: Option<usize>,
#[arg(long)]
pub(crate) lines: Option<String>,
#[arg(
long,
num_args = 0..=1,
default_missing_value = "true",
value_parser = clap::builder::BoolishValueParser::new()
)]
pub(crate) window: Option<bool>,
#[arg(
long,
num_args = 0..=1,
default_missing_value = "true",
value_parser = clap::builder::BoolishValueParser::new()
)]
pub(crate) show_line_numbers: Option<bool>,
#[arg(short = 'r', long = "border.radius")]
pub(crate) border_radius: Option<f32>,
#[arg(long = "border.width")]
pub(crate) border_width: Option<f32>,
#[arg(long = "border.color")]
pub(crate) border_color: Option<String>,
#[arg(long = "shadow.blur")]
pub(crate) shadow_blur: Option<f32>,
#[arg(long = "shadow.x")]
pub(crate) shadow_x: Option<f32>,
#[arg(long = "shadow.y")]
pub(crate) shadow_y: Option<f32>,
#[arg(long = "font.family")]
pub(crate) font_family: Option<String>,
#[arg(long = "font.file")]
pub(crate) font_file: Option<String>,
#[arg(long = "font.fallbacks", value_name = "LIST")]
pub(crate) font_fallbacks: Option<String>,
#[arg(long = "font.dirs", value_name = "LIST")]
pub(crate) font_dirs: Option<String>,
#[arg(long = "font.cjk-region", value_enum, alias = "font.cjk.region")]
pub(crate) font_cjk_region: Option<FontCjkRegionArg>,
#[arg(
long = "font.auto-download",
num_args = 0..=1,
default_missing_value = "true",
value_parser = clap::builder::BoolishValueParser::new()
)]
pub(crate) font_auto_download: Option<bool>,
#[arg(
long = "font.force-update",
num_args = 0..=1,
default_missing_value = "true",
value_parser = clap::builder::BoolishValueParser::new()
)]
pub(crate) font_force_update: Option<bool>,
#[arg(
long = "font.system-fallback",
value_enum,
alias = "font.system_fallback"
)]
pub(crate) font_system_fallback: Option<FontSystemFallbackArg>,
#[arg(long = "font.size")]
pub(crate) font_size: Option<f32>,
#[arg(long = "line-height")]
pub(crate) line_height: Option<f32>,
#[arg(long = "raster.scale")]
pub(crate) raster_scale: Option<f32>,
#[arg(long = "raster.max-pixels")]
pub(crate) raster_max_pixels: Option<u64>,
#[arg(long = "raster.backend", value_enum)]
pub(crate) raster_backend: Option<RasterBackendArg>,
#[arg(
long = "title",
num_args = 0..=1,
default_missing_value = "true",
value_parser = clap::builder::BoolishValueParser::new()
)]
pub(crate) title: Option<bool>,
#[arg(long = "title.text")]
pub(crate) title_text: Option<String>,
#[arg(long = "title.path-style", value_enum)]
pub(crate) title_path_style: Option<TitlePathStyleArg>,
#[arg(long = "title.tmux-format")]
pub(crate) title_tmux_format: Option<String>,
#[arg(long = "title.align", value_enum)]
pub(crate) title_align: Option<TitleAlignArg>,
#[arg(long = "title.size")]
pub(crate) title_size: Option<f32>,
#[arg(long = "title.color")]
pub(crate) title_color: Option<String>,
#[arg(long = "title.opacity")]
pub(crate) title_opacity: Option<f32>,
#[arg(long = "title.max-width")]
pub(crate) title_max_width: Option<usize>,
#[arg(long = "title.ellipsis")]
pub(crate) title_ellipsis: Option<String>,
#[arg(
long = "font.ligatures",
num_args = 0..=1,
default_missing_value = "true",
value_parser = clap::builder::BoolishValueParser::new()
)]
pub(crate) font_ligatures: Option<bool>,
#[arg(
long = "png-opt",
num_args = 0..=1,
default_missing_value = "true",
value_parser = clap::builder::BoolishValueParser::new()
)]
pub(crate) png_opt: Option<bool>,
#[arg(long = "png-opt-level")]
pub(crate) png_opt_level: Option<u8>,
#[arg(long = "png-strip", value_enum)]
pub(crate) png_strip: Option<PngStripArg>,
#[arg(
long = "png-quant",
num_args = 0..=1,
default_missing_value = "true",
value_parser = clap::builder::BoolishValueParser::new()
)]
pub(crate) png_quant: Option<bool>,
#[arg(long = "png-quant-quality")]
pub(crate) png_quant_quality: Option<u8>,
#[arg(long = "png-quant-speed")]
pub(crate) png_quant_speed: Option<u8>,
#[arg(long = "png-quant-dither")]
pub(crate) png_quant_dither: Option<f32>,
#[arg(long = "png-quant-preset", value_enum)]
pub(crate) png_quant_preset: Option<PngQuantPresetArg>,
#[arg(long = "execute.timeout")]
pub(crate) execute_timeout: Option<String>,
#[arg(short = 'x', long)]
pub(crate) execute: Option<String>,
#[arg(long)]
pub(crate) tmux: bool,
#[arg(long = "tmux-args", value_name = "ARGS", allow_hyphen_values = true)]
pub(crate) tmux_args: Option<String>,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub(crate) enum FormatArg {
Svg,
Png,
Webp,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub(crate) enum PngStripArg {
None,
Safe,
All,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub(crate) enum RasterBackendArg {
Auto,
Resvg,
Rsvg,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub(crate) enum FontSystemFallbackArg {
Auto,
Always,
Never,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub(crate) enum FontCjkRegionArg {
Auto,
Sc,
Tc,
Hk,
Jp,
Kr,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub(crate) enum PngQuantPresetArg {
Fast,
Balanced,
Best,
}
impl From<PngStripArg> for PngStrip {
fn from(value: PngStripArg) -> Self {
match value {
PngStripArg::None => PngStrip::None,
PngStripArg::Safe => PngStrip::Safe,
PngStripArg::All => PngStrip::All,
}
}
}
impl From<RasterBackendArg> for RasterBackend {
fn from(value: RasterBackendArg) -> Self {
match value {
RasterBackendArg::Auto => RasterBackend::Auto,
RasterBackendArg::Resvg => RasterBackend::Resvg,
RasterBackendArg::Rsvg => RasterBackend::Rsvg,
}
}
}
impl From<FontSystemFallbackArg> for FontSystemFallback {
fn from(value: FontSystemFallbackArg) -> Self {
match value {
FontSystemFallbackArg::Auto => FontSystemFallback::Auto,
FontSystemFallbackArg::Always => FontSystemFallback::Always,
FontSystemFallbackArg::Never => FontSystemFallback::Never,
}
}
}
impl From<FontCjkRegionArg> for CjkRegion {
fn from(value: FontCjkRegionArg) -> Self {
match value {
FontCjkRegionArg::Auto => CjkRegion::Auto,
FontCjkRegionArg::Sc => CjkRegion::Sc,
FontCjkRegionArg::Tc => CjkRegion::Tc,
FontCjkRegionArg::Hk => CjkRegion::Hk,
FontCjkRegionArg::Jp => CjkRegion::Jp,
FontCjkRegionArg::Kr => CjkRegion::Kr,
}
}
}
impl From<PngQuantPresetArg> for PngQuantPreset {
fn from(value: PngQuantPresetArg) -> Self {
match value {
PngQuantPresetArg::Fast => PngQuantPreset::Fast,
PngQuantPresetArg::Balanced => PngQuantPreset::Balanced,
PngQuantPresetArg::Best => PngQuantPreset::Best,
}
}
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub(crate) enum TitleAlignArg {
Left,
Center,
Right,
}
impl From<TitleAlignArg> for TitleAlign {
fn from(value: TitleAlignArg) -> Self {
match value {
TitleAlignArg::Left => TitleAlign::Left,
TitleAlignArg::Center => TitleAlign::Center,
TitleAlignArg::Right => TitleAlign::Right,
}
}
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub(crate) enum TitlePathStyleArg {
Absolute,
Relative,
Basename,
}
impl From<TitlePathStyleArg> for TitlePathStyle {
fn from(value: TitlePathStyleArg) -> Self {
match value {
TitlePathStyleArg::Absolute => TitlePathStyle::Absolute,
TitlePathStyleArg::Relative => TitlePathStyle::Relative,
TitlePathStyleArg::Basename => TitlePathStyle::Basename,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn arg_enum_conversions_cover_variants() {
assert!(matches!(PngStrip::from(PngStripArg::None), PngStrip::None));
assert!(matches!(PngStrip::from(PngStripArg::Safe), PngStrip::Safe));
assert!(matches!(PngStrip::from(PngStripArg::All), PngStrip::All));
assert!(matches!(
RasterBackend::from(RasterBackendArg::Auto),
RasterBackend::Auto
));
assert!(matches!(
RasterBackend::from(RasterBackendArg::Resvg),
RasterBackend::Resvg
));
assert!(matches!(
RasterBackend::from(RasterBackendArg::Rsvg),
RasterBackend::Rsvg
));
assert!(matches!(
FontSystemFallback::from(FontSystemFallbackArg::Auto),
FontSystemFallback::Auto
));
assert!(matches!(
FontSystemFallback::from(FontSystemFallbackArg::Always),
FontSystemFallback::Always
));
assert!(matches!(
FontSystemFallback::from(FontSystemFallbackArg::Never),
FontSystemFallback::Never
));
assert!(matches!(
CjkRegion::from(FontCjkRegionArg::Auto),
CjkRegion::Auto
));
assert!(matches!(
CjkRegion::from(FontCjkRegionArg::Sc),
CjkRegion::Sc
));
assert!(matches!(
CjkRegion::from(FontCjkRegionArg::Tc),
CjkRegion::Tc
));
assert!(matches!(
CjkRegion::from(FontCjkRegionArg::Hk),
CjkRegion::Hk
));
assert!(matches!(
CjkRegion::from(FontCjkRegionArg::Jp),
CjkRegion::Jp
));
assert!(matches!(
CjkRegion::from(FontCjkRegionArg::Kr),
CjkRegion::Kr
));
assert!(matches!(
PngQuantPreset::from(PngQuantPresetArg::Fast),
PngQuantPreset::Fast
));
assert!(matches!(
PngQuantPreset::from(PngQuantPresetArg::Balanced),
PngQuantPreset::Balanced
));
assert!(matches!(
PngQuantPreset::from(PngQuantPresetArg::Best),
PngQuantPreset::Best
));
assert!(matches!(
TitleAlign::from(TitleAlignArg::Left),
TitleAlign::Left
));
assert!(matches!(
TitleAlign::from(TitleAlignArg::Center),
TitleAlign::Center
));
assert!(matches!(
TitleAlign::from(TitleAlignArg::Right),
TitleAlign::Right
));
assert!(matches!(
TitlePathStyle::from(TitlePathStyleArg::Absolute),
TitlePathStyle::Absolute
));
assert!(matches!(
TitlePathStyle::from(TitlePathStyleArg::Relative),
TitlePathStyle::Relative
));
assert!(matches!(
TitlePathStyle::from(TitlePathStyleArg::Basename),
TitlePathStyle::Basename
));
}
}