Skip to main content

yog_cli/design/
mod_ui.rs

1//! A mod's `.yui` that books and recipes use — its kinds of book page
2//! (`book_page`) and its recipe layouts (`recipe_layout`) — read with
3//! yog-book's own reader and compiler, as `yog build` reads them.
4
5use yog_ids::Format;
6use std::path::{Path, PathBuf};
7
8use yog_formats::book::layout::RecipeLayout;
9use yog_formats::book::page_type::PageType;
10use yog_formats::yui::Element;
11
12/// Every `src/**/*.yui` of the mod at `root`, parsed (broken ones left out).
13fn trees(root: &Path) -> Vec<(PathBuf, Element)> {
14    let mut out: Vec<(PathBuf, Element)> = ignore::WalkBuilder::new(root.join("src"))
15        .hidden(false)
16        .build()
17        .flatten()
18        .map(|e| e.into_path())
19        .filter(|p| p.is_file() && Format::Ui.is(p))
20        .filter_map(|p| {
21            let text = std::fs::read_to_string(&p).ok()?;
22            Some((p, yog_formats::yui::parse(&text).ok()?))
23        })
24        .collect();
25    out.sort_by(|a, b| a.0.cmp(&b.0));
26    out
27}
28
29pub fn ns(root: &Path) -> String {
30    crate::design::project::mod_id(root).unwrap_or_else(|| yog_ids::ns::MINECRAFT.into())
31}
32
33/// The mod's recipe layouts and the files they're in.
34pub fn recipe_layouts(root: &Path) -> Vec<(PathBuf, RecipeLayout)> {
35    let ns = ns(root);
36    trees(root)
37        .into_iter()
38        .filter(|(_, el)| yog_formats::book::layout::is_recipe_layout(el))
39        .filter_map(|(p, el)| Some((p, yog_formats::book::layout::compile(&el, &ns).ok()?)))
40        .collect()
41}
42
43/// The mod's kinds of book page.
44pub fn page_types(root: &Path) -> Vec<PageType> {
45    let ns = ns(root);
46    trees(root)
47        .into_iter()
48        .filter(|(_, el)| yog_formats::book::page_type::is_book_page(el))
49        .filter_map(|(_, el)| yog_formats::book::page_type::compile(&el, &ns).ok())
50        .collect()
51}
52
53#[cfg(test)]
54mod tests {
55    #[test]
56    fn reads_the_mods_layouts_and_page_types() {
57        let dir = std::env::temp_dir().join(format!("yog-idle-mod-ui-{}", std::process::id()));
58        let _ = std::fs::remove_dir_all(&dir);
59        std::fs::create_dir_all(dir.join("src/ui")).unwrap();
60        std::fs::write(dir.join("yog.toml"), "[mod]\nid = \"mymod\"\n").unwrap();
61        std::fs::write(
62            dir.join("src/ui/crusher.yui"),
63            r#"<Component recipe_layout="crusher" width="60" height="24"><RecipeSlot slot="input" x="4" y="4"/><RecipeResult x="40" y="4"/></Component>"#,
64        )
65        .unwrap();
66        std::fs::write(dir.join("src/ui/page.yui"), r#"<Component book_page="note"><Property name="t" type="book_text"/><BookText text="{x:Bind t}"/></Component>"#).unwrap();
67        std::fs::write(dir.join("src/ui/screen.yui"), r#"<Screen width="10" height="10"/>"#).unwrap();
68        let l = super::recipe_layouts(&dir);
69        assert_eq!(l.len(), 1);
70        assert_eq!(l[0].1.kinds, ["mymod:crusher"]);
71        assert_eq!(super::page_types(&dir)[0].id, "mymod:note");
72        let _ = std::fs::remove_dir_all(&dir);
73    }
74}