diff --git a/species/blobcat/templates/hand-boop.mustache b/species/blobcat/templates/hand-boop.mustache
index 7ac88f4..4b256b0 100644
--- a/species/blobcat/templates/hand-boop.mustache
+++ b/species/blobcat/templates/hand-boop.mustache
@@ -1,3 +1,3 @@
- {{#boop_owo}}#hand-boop{{/boop_owo}}
+ {{>parent.hand-boop}}
diff --git a/species/blobcat/templates/hands.mustache b/species/blobcat/templates/hands.mustache
index 62c1b4e..48cf6f3 100644
--- a/species/blobcat/templates/hands.mustache
+++ b/species/blobcat/templates/hands.mustache
@@ -1,16 +1,3 @@
-{{! TODO: use parent }}
-
- {{#tags.hands-reach}}
- {{#set-fill}}#fcc21b|{{#reach_aww}}#left-hand{{/reach_aww}}{{/set-fill}}
- {{#set-fill}}#fcc21b|{{#reach_aww}}#right-hand{{/reach_aww}}{{/set-fill}}
- {{/tags.hands-reach}}
- {{#tags.hand-3c}}
- {{#tags.holding}}
- {{#set-fill}}#fcc21b|{{#knife}}#left-hand{{/knife}}{{/set-fill}}
- {{/tags.holding}}
- {{^tags.holding}}
- {{! :3c hand }}
- {{#set-fill}}#fcc21b|{{#3c_evil}}#left-hand{{/3c_evil}}{{/set-fill}}
- {{/tags.holding}}
- {{/tags.hand-3c}}
-
+{{#set-fill}}
+ #fcc21b | {{>parent.hands}}
+{{/set-fill}}
diff --git a/species/blobcat/templates/mouth.mustache b/species/blobcat/templates/mouth.mustache
index b7fc2fa..660cb04 100644
--- a/species/blobcat/templates/mouth.mustache
+++ b/species/blobcat/templates/mouth.mustache
@@ -1,9 +1,7 @@
{{#tags.boop}}
{{/tags.boop}}
- {{#tags.mouth-w}}
- {{#base}}#mouth{{/base}}
- {{/tags.mouth-w}}
+ {{>parent.mouth}}
{{#tags.boop}}
{{/tags.boop}}
diff --git a/species/blobcat/templates/nose.mustache b/species/blobcat/templates/nose.mustache
index 0e08567..cbe2790 100644
--- a/species/blobcat/templates/nose.mustache
+++ b/species/blobcat/templates/nose.mustache
@@ -1,13 +1,13 @@
{{#tags.body-snug}}
-
- {{#snug}}#nose{{/snug}}
+
+ {{>parent.nose}}
{{/tags.body-snug}}
{{^tags.body-snug}}
{{#tags.boop}}
-
- {{#snug}}#nose{{/snug}}
+
+ {{>parent.nose}}
{{/tags.boop}}
{{/tags.body-snug}}
diff --git a/species/blobcat/templates/tail.mustache b/species/blobcat/templates/tail.mustache
index 28c29d7..52e0027 100644
--- a/species/blobcat/templates/tail.mustache
+++ b/species/blobcat/templates/tail.mustache
@@ -1 +1 @@
-{{#set-fill}}#fcc21b|{{#snug}}#tail{{/snug}}{{/set-fill}}
+{{#set-fill}}#fcc21b|{{>parent.tail}}{{/set-fill}}
diff --git a/src/main.rs b/src/main.rs
index 06f9c67..b25f515 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,3 @@
-use std::sync::Arc;
use clap::Parser;
use std::path::PathBuf;
@@ -14,7 +13,7 @@ use export::*;
fn main() {
let args = Args::parse();
- let species = Arc::new(load_species(args.decl.clone()).unwrap());
+ let species = load_species(args.decl.clone()).unwrap();
let context = RenderingContext::new(species);
let output_dir = args.output_dir.clone().unwrap_or(PathBuf::from("output/"));
diff --git a/src/parse.rs b/src/parse.rs
index 1cfe013..3567cbd 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -42,6 +42,9 @@ pub struct SpeciesDecl {
#[serde(skip)]
pub asset_paths: HashMap,
+
+ #[serde(skip)]
+ pub parent: Option>,
}
/// Loads the given file as an XML tree
@@ -66,10 +69,11 @@ pub fn load_species(path: impl AsRef) -> Result {
let path = path.as_ref().to_path_buf().join(base);
let base = load_species(path)?;
- res.template_paths = base.template_paths;
- res.variant_paths = base.variant_paths;
- res.asset_paths = base.asset_paths;
- res.variants = base.variants;
+ res.template_paths = base.template_paths.clone();
+ res.variant_paths = base.variant_paths.clone();
+ res.asset_paths = base.asset_paths.clone();
+ res.variants = base.variants.clone();
+ res.parent = Some(Box::new(base));
}
// Read the `templates` directory and populate the `template_paths` field;
diff --git a/src/template.rs b/src/template.rs
index 59d20fa..d775f56 100644
--- a/src/template.rs
+++ b/src/template.rs
@@ -12,14 +12,21 @@ pub struct RenderingContext {
rendered_variants: Arc>>,
loaded_assets: Arc>>,
+
+ parent: Option>,
}
impl RenderingContext {
- pub fn new(species: Arc) -> Self {
+ pub fn new(mut species: SpeciesDecl) -> Self {
+ let parent = std::mem::take(&mut species.parent).map(|parent| {
+ Box::new(Self::new(*parent))
+ });
+
Self {
- species,
+ species: Arc::new(species),
rendered_variants: Arc::new(Mutex::new(HashMap::new())),
loaded_assets: Arc::new(Mutex::new(HashMap::new())),
+ parent
}
}
@@ -39,6 +46,10 @@ impl RenderingContext {
}
pub fn get_data(&self, variant_name: &str) -> Data {
+ self.get_builder(variant_name).build()
+ }
+
+ fn get_builder(&self, variant_name: &str) -> MapBuilder {
let mut builder = MapBuilder::new();
builder = builder.insert_map("variant", |mut builder| {
@@ -92,16 +103,7 @@ impl RenderingContext {
// Convert `xml` to XML
match Element::parse(xml.as_bytes()) {
Ok(mut xml) => {
- // Substitute the fill color
- if let Some(style) = xml.attributes.get("style") {
- xml.attributes.insert(
- "style".to_string(),
- format!("{};fill: {};", style, color),
- );
- }
- if let Some(_fill) = xml.attributes.get("fill") {
- xml.attributes.insert("fill".to_string(), color);
- }
+ set_fill(&color.trim(), &mut xml);
// Render XML to string
if let Some(res) = xml_to_string(xml) {
@@ -122,6 +124,16 @@ impl RenderingContext {
}
});
+ if let Some(ref parent) = self.parent {
+ let parent = parent.clone();
+ let variant_name = variant_name.to_string();
+ builder = builder.insert_map("parent", move |_| {
+ parent.get_builder(&variant_name)
+ });
+ }
+
+ // TODO: memoize the builder to this stage
+
// Variant tags
if let Some(tags) = self.species.variants.get(variant_name) {
builder = builder.insert_map("tags", move |mut builder| {
@@ -133,7 +145,7 @@ impl RenderingContext {
});
}
- builder.build()
+ builder
}
pub fn get_variant(&self, name: &String) -> Option {
@@ -185,6 +197,12 @@ impl PartialLoader for RenderingContext {
fn load(&self, name: impl AsRef) -> Result {
let name = name.as_ref().to_str().ok_or(mustache::Error::InvalidStr)?;
+ if let Some(ref parent) = self.parent {
+ if name.starts_with("parent.") {
+ return parent.load(&name[7..]);
+ }
+ }
+
if let Some(path) = self.species.template_paths.get(name) {
Ok(std::fs::read_to_string(path)?)
} else {
@@ -194,6 +212,25 @@ impl PartialLoader for RenderingContext {
}
}
+fn set_fill(color: &str, xml: &mut Element) {
+ // Substitute the fill color
+ if let Some(style) = xml.attributes.get("style") {
+ xml.attributes.insert(
+ "style".to_string(),
+ format!("{};fill: {};", style, color),
+ );
+ }
+ if let Some(_fill) = xml.attributes.get("fill") {
+ xml.attributes.insert("fill".to_string(), color.to_string());
+ }
+
+ for child in xml.children.iter_mut() {
+ if let XMLNode::Element(ref mut child) = child {
+ set_fill(color, child);
+ }
+ }
+}
+
pub fn query_selector(svg: Element, pattern: &str) -> Option {
if pattern == "" {
return Some(svg);