//! CLI Functionality abstractions #![allow(unused)] use anyhow::Result; use log::trace; use serde::Serialize; use std::fmt::Debug; use std::path::Path; use std::str::FromStr; use std::{collections::HashMap, convert::TryFrom}; use subplot::{Document, EmbeddedFile, Style, SubplotError}; pub fn extract_file<'a>(doc: &'a Document, filename: &str) -> Result<&'a EmbeddedFile> { for file in doc.files() { if file.filename() == filename { return Ok(file); } } Err(SubplotError::EmbeddedFileNotFound(filename.to_owned()).into()) } #[derive(Serialize)] pub struct Metadata { sources: Vec, title: String, binding_files: Vec, impls: HashMap>, bibliographies: Vec, scenarios: Vec, files: Vec, } impl TryFrom<&mut Document> for Metadata { type Error = subplot::SubplotError; fn try_from(doc: &mut Document) -> std::result::Result { let mut sources: Vec<_> = doc .sources(None) .into_iter() .map(|p| filename(Some(&p))) .collect(); sources.sort_unstable(); let title = doc.meta().title().to_owned(); let mut binding_files: Vec<_> = doc .meta() .bindings_filenames() .into_iter() .map(|p| filename(Some(p))) .collect(); binding_files.sort_unstable(); let impls: HashMap<_, _> = doc .meta() .templates() .map(|template| { let mut filenames: Vec<_> = doc .meta() .document_impl(template) .unwrap() .functions_filenames() .map(|p| filename(Some(p))) .collect(); filenames.sort_unstable(); (template.to_string(), filenames) }) .collect(); let mut bibliographies: Vec<_> = doc .meta() .bibliographies() .into_iter() .map(|p| filename(Some(p))) .collect(); bibliographies.sort_unstable(); let mut scenarios: Vec<_> = doc .scenarios()? .into_iter() .map(|s| s.title().to_owned()) .collect(); scenarios.sort_unstable(); let mut files: Vec<_> = doc .files() .iter() .map(|f| f.filename().to_owned()) .collect(); files.sort_unstable(); Ok(Self { sources, title, binding_files, impls, bibliographies, scenarios, files, }) } } impl Metadata { fn write_list(v: &[String], prefix: &str) { v.iter().for_each(|entry| println!("{}: {}", prefix, entry)) } pub fn write_out(&self) { Self::write_list(&self.sources, "source"); println!("title: {}", self.title); Self::write_list(&self.binding_files, "bindings"); let templates: Vec = self.impls.keys().map(String::from).collect(); Self::write_list(&templates, "templates"); for (template, filenames) in self.impls.iter() { Self::write_list(filenames, &format!("functions[{}]", template)); } Self::write_list(&self.bibliographies, "bibliography"); Self::write_list(&self.files, "file"); Self::write_list(&self.scenarios, "scenario"); } } fn filename(name: Option<&Path>) -> String { let path = match name { None => return "".to_string(), Some(x) => x, }; match path.to_str() { None => "non-UTF8 filename".to_string(), Some(x) => x.to_string(), } } #[derive(Debug)] pub enum OutputFormat { Plain, Json, } impl FromStr for OutputFormat { type Err = String; fn from_str(s: &str) -> std::result::Result { match s.to_ascii_lowercase().as_ref() { "plain" => Ok(OutputFormat::Plain), "json" => Ok(OutputFormat::Json), _ => Err(format!("Unknown output format: `{}`", s)), } } }