use super::Printer;
use crate::cli::CliOptions;
use crate::info::Info;
use crate::info::langs::language::Language;
use crate::ui::printer::{PrinterType, SerializationFormat};
use anyhow::{Context, Result};
use image::DynamicImage;
use onefetch_image::ImageBackend;
pub struct PrinterFactory {
pub output: Option<SerializationFormat>,
pub info: Info,
image: Option<DynamicImage>,
pub no_bold: bool,
pub art_off: bool,
image_backend: Option<Box<dyn ImageBackend>>,
color_resolution: usize,
ascii_input: Option<String>,
ascii_language: Option<Language>,
}
impl PrinterFactory {
pub fn new(info: Info, cli_options: CliOptions) -> Result<Self> {
let image =
match cli_options.image.image {
Some(p) => Some(image::open(&p).with_context(|| {
format!("Could not load the image file at '{}'", p.display())
})?),
None => None,
};
let image_backend = if image.is_some() {
cli_options
.image
.image_protocol
.map_or_else(onefetch_image::get_best_backend, |s| {
Ok(onefetch_image::get_image_backend(s))
})?
} else {
None
};
Ok(Self {
output: cli_options.developer.output,
info,
image,
no_bold: cli_options.text_formatting.no_bold,
art_off: cli_options.visuals.no_art,
image_backend,
color_resolution: cli_options.image.color_resolution,
ascii_input: cli_options.ascii.ascii_input,
ascii_language: cli_options.ascii.ascii_language,
})
}
pub fn create(self) -> Result<Printer> {
let PrinterFactory {
output,
info,
image,
no_bold,
art_off,
image_backend,
color_resolution,
ascii_input,
ascii_language,
} = self;
match output {
Some(SerializationFormat::Json) => Ok(Printer {
r#type: PrinterType::Json,
info,
}),
Some(SerializationFormat::Yaml) => Ok(Printer {
r#type: PrinterType::Yaml,
info,
}),
None => {
if art_off {
Ok(Printer {
r#type: PrinterType::Plain,
info,
})
} else if let Some(image) = image {
Ok(Printer {
r#type: PrinterType::Image {
image,
backend: image_backend.context("No supported image backend")?,
resolution: color_resolution,
},
info,
})
} else {
let ascii_art = ascii_input
.or_else(|| {
ascii_language.map(|language| language.get_ascii_art().to_string())
})
.or_else(|| {
info.dominant_language
.as_ref()
.map(|language| language.get_ascii_art().to_string())
});
if let Some(art) = ascii_art {
Ok(Printer {
r#type: PrinterType::Ascii { art, no_bold },
info,
})
} else {
Ok(Printer {
r#type: PrinterType::Plain,
info,
})
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use crate::{
cli::CliOptions,
info::{Info, langs::language::Language},
ui::printer::{PrinterType, SerializationFormat, factory::PrinterFactory},
};
use image::DynamicImage;
#[test]
fn test_create_json_printer() {
let info = Info::default();
let mut options = CliOptions::default();
options.developer.output = Some(SerializationFormat::Json);
let factory = PrinterFactory::new(info, options).unwrap();
let printer = factory.create().unwrap();
assert_eq!(printer.r#type, PrinterType::Json);
}
#[test]
fn test_create_yaml_printer() {
let info = Info::default();
let mut options = CliOptions::default();
options.developer.output = Some(SerializationFormat::Yaml);
let factory = PrinterFactory::new(info, options).unwrap();
let printer = factory.create().unwrap();
assert_eq!(printer.r#type, PrinterType::Yaml);
}
#[test]
fn test_create_plain_printer_when_no_art() {
let mut info = Info::default();
info.dominant_language = Some(Language::Rust);
let mut options = CliOptions::default();
options.visuals.no_art = true;
let factory = PrinterFactory::new(info, options).unwrap();
let printer = factory.create().unwrap();
assert_eq!(printer.r#type, PrinterType::Plain);
}
#[test]
fn test_create_plain_printer_when_no_dominant_language_no_ascii_input() {
let info = Info::default();
let options = CliOptions::default();
let factory = PrinterFactory::new(info, options).unwrap();
let printer = factory.create().unwrap();
assert_eq!(printer.r#type, PrinterType::Plain);
}
#[test]
fn test_create_ascii_printer_when_dominant_language() {
let mut info = Info::default();
info.dominant_language = Some(Language::Rust);
let options = CliOptions::default();
let factory = PrinterFactory::new(info, options).unwrap();
let printer = factory.create().unwrap();
assert!(matches!(printer.r#type, PrinterType::Ascii { .. }));
}
#[test]
fn test_create_ascii_printer_when_ascii_language_without_dominant_language() {
let info = Info::default();
let mut options = CliOptions::default();
options.ascii.ascii_language = Some(Language::Rust);
let factory = PrinterFactory::new(info, options).unwrap();
let printer = factory.create().unwrap();
assert!(matches!(printer.r#type, PrinterType::Ascii { .. }));
}
pub struct DummyBackend {}
impl DummyBackend {
pub fn new() -> Self {
Self {}
}
}
impl super::ImageBackend for DummyBackend {
fn add_image(
&self,
_lines: Vec<String>,
_image: &DynamicImage,
_colors: usize,
) -> anyhow::Result<String> {
Ok("foo".to_string())
}
}
#[test]
fn test_create_image_printer() {
let factory = PrinterFactory {
output: None,
info: Info::default(),
image: Some(DynamicImage::default()),
no_bold: false,
art_off: false,
image_backend: Some(Box::new(DummyBackend::new())),
color_resolution: 8,
ascii_input: None,
ascii_language: None,
};
let printer = factory.create().unwrap();
assert!(matches!(printer.r#type, PrinterType::Image { .. }));
}
}