From e741180b13826331c886b996423df80b62da4f25 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sun, 22 Jan 2023 11:33:51 +0200 Subject: refactor: create Metadata from YamlMetadata without pandoc_ast We don't want to use pandoc_ast outside of the md module. Sponsored-by: author --- src/ast.rs | 55 ++++++++++++++ src/metadata.rs | 230 ++++++++++---------------------------------------------- 2 files changed, 93 insertions(+), 192 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index c48a1e7..b60df71 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -60,6 +60,7 @@ impl YamlMetadata { fn new(yaml_text: &str) -> Result { trace!("Parsing YAML"); let meta: Self = serde_yaml::from_str(yaml_text)?; + trace!("parsed metadata: {:#?}", meta); Ok(meta) } @@ -68,6 +69,60 @@ impl YamlMetadata { &self.markdowns[0] } + /// Title. + pub fn title(&self) -> &str { + &self.title + } + + /// Subtitle. + pub fn subtitle(&self) -> Option<&str> { + self.subtitle.as_deref() + } + + /// Date. + pub fn date(&self) -> Option<&str> { + self.date.as_deref() + } + + /// Authors. + pub fn authors(&self) -> Option<&[String]> { + self.authors.as_deref() + } + + /// Names of bindings files. + pub fn bindings_filenames(&self) -> Option<&[PathBuf]> { + self.bindings.as_deref() + } + + /// Impls section. + pub fn impls(&self) -> &BTreeMap> { + &self.impls + } + + /// Bibliographies. + pub fn bibliographies(&self) -> Option<&[PathBuf]> { + self.bibliography.as_deref() + } + + /// Classes.. + pub fn classes(&self) -> Option<&[String]> { + self.classes.as_deref() + } + + /// Documentclass. + pub fn documentclass(&self) -> Option<&str> { + self.documentclass.as_deref() + } + + /// Pandoc metadata. + pub fn pandoc(&self) -> Option<&HashMap> { + if let Some(x) = &self.pandoc { + Some(x) + } else { + None + } + } + /// Convert into a pandoc_ast::Map. pub fn to_map(&self) -> Map { trace!("Creating metadata map from parsed YAML"); diff --git a/src/metadata.rs b/src/metadata.rs index 261017a..e88c732 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -1,14 +1,11 @@ use crate::{Bindings, SubplotError, TemplateSpec, YamlMetadata}; +use log::trace; use std::collections::HashMap; use std::fmt::Debug; use std::ops::Deref; use std::path::{Path, PathBuf}; -use pandoc_ast::{Inline, Map, MetaValue}; - -use log::trace; - /// Metadata of a document, as needed by Subplot. #[derive(Debug)] pub struct Metadata { @@ -31,60 +28,58 @@ pub struct DocumentImpl { } impl Metadata { - /// Construct a Metadata from a Document, if possible. - pub fn new

( + /// Create from YamlMetadata. + pub fn from_yaml_metadata

( basedir: P, - meta: &YamlMetadata, + yaml: &YamlMetadata, template: Option<&str>, - ) -> Result + ) -> Result where P: AsRef + Debug, { - let map = meta.to_map(); - let title = get_title(&map); - let date = get_date(&map); - let bindings_filenames = get_bindings_filenames(&map); - let bibliographies = get_bibliographies(basedir.as_ref(), &map); - let classes = get_classes(&map); - trace!("Loaded basic metadata"); + let mut bindings = Bindings::new(); + let bindings_filenames = if let Some(filenames) = yaml.bindings_filenames() { + get_bindings(filenames, &mut bindings, template)?; + filenames.iter().map(|p| p.to_path_buf()).collect() + } else { + vec![] + }; let mut impls = HashMap::new(); - if let Some(raw_impls) = map.get("impls") { - match raw_impls { - MetaValue::MetaMap(raw_impls) => { - for (impl_name, functions_filenames) in raw_impls.iter() { - let template_spec = load_template_spec(impl_name)?; - let filenames = pathbufs("", functions_filenames); - let docimpl = DocumentImpl::new(template_spec, filenames); - impls.insert(impl_name.to_string(), docimpl); - } - } - _ => { - trace!("Ignoring unknown raw implementation value"); - } - } + for (impl_name, functions_filenames) in yaml.impls().iter() { + let template_spec = load_template_spec(impl_name)?; + let filenames = pathbufs("", functions_filenames); + let docimpl = DocumentImpl::new(template_spec, filenames); + impls.insert(impl_name.to_string(), docimpl); } - let template = template.or_else(|| impls.keys().next().map(String::as_str)); - - let mut bindings = Bindings::new(); + let bibliographies = if let Some(v) = yaml.bibliographies() { + v.iter().map(|s| s.to_path_buf()).collect() + } else { + vec![] + }; - get_bindings(&bindings_filenames, &mut bindings, template)?; + let classes = if let Some(v) = yaml.classes() { + v.iter().map(|s| s.to_string()).collect() + } else { + vec![] + }; - trace!("Loaded all metadata successfully"); - - Ok(Metadata { + let meta = Self { basedir: basedir.as_ref().to_path_buf(), - title, - date, - markdown_filename: meta.markdown().into(), + title: yaml.title().into(), + date: yaml.date().map(|s| s.into()), + markdown_filename: yaml.markdown().into(), bindings_filenames, bindings, impls, bibliographies, classes, - }) + }; + trace!("metadata: {:#?}", meta); + + Ok(meta) } /// Return title of document. @@ -152,24 +147,6 @@ impl DocumentImpl { } } -type Mapp = Map; - -fn get_title(map: &Mapp) -> String { - if let Some(s) = get_string(map, "title") { - s - } else { - "".to_string() - } -} - -fn get_date(map: &Mapp) -> Option { - get_string(map, "date") -} - -fn get_bindings_filenames(map: &Mapp) -> Vec { - get_paths("", map, "bindings") -} - fn load_template_spec(template: &str) -> Result { let mut spec_path = PathBuf::from(template); spec_path.push("template"); @@ -177,143 +154,12 @@ fn load_template_spec(template: &str) -> Result { TemplateSpec::from_file(&spec_path) } -fn get_paths

(basedir: P, map: &Mapp, field: &str) -> Vec -where - P: AsRef, -{ - match map.get(field) { - None => vec![], - Some(v) => pathbufs(basedir, v), - } -} - -fn get_string(map: &Mapp, field: &str) -> Option { - let v = match map.get(field) { - None => return None, - Some(s) => s, - }; - let v = match v { - pandoc_ast::MetaValue::MetaString(s) => s.to_string(), - pandoc_ast::MetaValue::MetaInlines(vec) => join(vec), - _ => panic!("don't know how to handle: {:?}", v), - }; - Some(v) -} - -fn get_bibliographies

(basedir: P, map: &Mapp) -> Vec -where - P: AsRef, -{ - let v = match map.get("bibliography") { - None => return vec![], - Some(s) => s, - }; - pathbufs(basedir, v) -} - -fn pathbufs

(basedir: P, v: &MetaValue) -> Vec -where - P: AsRef, -{ - let mut bufs = vec![]; - push_pathbufs(basedir, v, &mut bufs); - bufs -} - -fn get_classes(map: &Mapp) -> Vec { - let mut ret = Vec::new(); - if let Some(classes) = map.get("classes") { - push_strings(classes, &mut ret); - } - ret -} - -fn push_strings(v: &MetaValue, strings: &mut Vec) { - match v { - MetaValue::MetaString(s) => strings.push(s.to_string()), - MetaValue::MetaInlines(vec) => strings.push(join(vec)), - MetaValue::MetaList(values) => { - for value in values { - push_strings(value, strings); - } - } - _ => panic!("don't know how to handle: {:?}", v), - }; -} - -fn push_pathbufs

(basedir: P, v: &MetaValue, bufs: &mut Vec) +fn pathbufs

(basedir: P, v: &[PathBuf]) -> Vec where P: AsRef, { - match v { - MetaValue::MetaString(s) => bufs.push(basedir.as_ref().join(Path::new(s))), - MetaValue::MetaInlines(vec) => bufs.push(basedir.as_ref().join(Path::new(&join(vec)))), - MetaValue::MetaList(values) => { - for value in values { - push_pathbufs(basedir.as_ref(), value, bufs); - } - } - _ => panic!("don't know how to handle: {:?}", v), - }; -} - -fn join(vec: &[Inline]) -> String { - let mut buf = String::new(); - join_into_buffer(vec, &mut buf); - buf -} - -fn join_into_buffer(vec: &[Inline], buf: &mut String) { - for item in vec { - match item { - pandoc_ast::Inline::Str(s) => buf.push_str(s), - pandoc_ast::Inline::Code(_, s) => buf.push_str(s), - pandoc_ast::Inline::Emph(v) => join_into_buffer(v, buf), - pandoc_ast::Inline::Strong(v) => join_into_buffer(v, buf), - pandoc_ast::Inline::Strikeout(v) => join_into_buffer(v, buf), - pandoc_ast::Inline::Superscript(v) => join_into_buffer(v, buf), - pandoc_ast::Inline::Subscript(v) => join_into_buffer(v, buf), - pandoc_ast::Inline::SmallCaps(v) => join_into_buffer(v, buf), - pandoc_ast::Inline::Space => buf.push(' '), - pandoc_ast::Inline::SoftBreak => buf.push(' '), - pandoc_ast::Inline::LineBreak => buf.push(' '), - pandoc_ast::Inline::Quoted(qtype, v) => { - let quote = match qtype { - pandoc_ast::QuoteType::SingleQuote => '\'', - pandoc_ast::QuoteType::DoubleQuote => '"', - }; - buf.push(quote); - join_into_buffer(v, buf); - buf.push(quote); - } - _ => panic!("unknown pandoc_ast::Inline component {:?}", item), - } - } -} - -#[cfg(test)] -mod test_join { - use super::join; - use pandoc_ast::{Inline, QuoteType}; - - #[test] - fn join_all_kinds() { - let v = vec![ - Inline::Str("a".to_string()), - Inline::Emph(vec![Inline::Str("b".to_string())]), - Inline::Strong(vec![Inline::Str("c".to_string())]), - Inline::Strikeout(vec![Inline::Str("d".to_string())]), - Inline::Superscript(vec![Inline::Str("e".to_string())]), - Inline::Subscript(vec![Inline::Str("f".to_string())]), - Inline::SmallCaps(vec![Inline::Str("g".to_string())]), - Inline::Space, - Inline::SoftBreak, - Inline::Quoted(QuoteType::SingleQuote, vec![Inline::Str("h".to_string())]), - Inline::LineBreak, - Inline::Quoted(QuoteType::DoubleQuote, vec![Inline::Str("i".to_string())]), - ]; - assert_eq!(join(&v), r#"abcdefg 'h' "i""#); - } + let basedir = basedir.as_ref(); + v.iter().map(|p| basedir.join(p)).collect() } fn get_bindings

( -- cgit v1.2.1