wty 0.8.2

Yomitan-compatible dictionaries from wikitionary data
Documentation
use std::{
    fs::{self},
    path::PathBuf,
};

use anyhow::Result;
use pangloss::{
    AltEntry, AltMap, Definition, Entry, Glossary, GlossaryInfo, Writer,
    formats::stardict::StardictFormat,
};

use crate::{
    cli::Options,
    dict::writer::renderer::Renderer,
    lang::Lang,
    models::yomitan::{DetailedDefinition, YomitanDict},
    path::PathManager,
};

mod renderer;
use renderer::StardictRenderer;

pub fn write_stardict(
    source: Lang,
    target: Lang,
    _: &Options,
    pm: &PathManager,
    ydict: YomitanDict,
) -> Result<PathBuf> {
    let dir_in_stage = pm.dir_in_stage("stardict");
    _ = fs::create_dir_all(&dir_in_stage);

    let dict_name = format!("wty-{source}-{target}");
    let ifo_path = dir_in_stage.join(format!("{dict_name}.ifo"));
    let glossary = build_glossary(&dict_name, ydict);

    StardictFormat.write(&ifo_path, &glossary)?;

    Ok(dir_in_stage)
}

// Build a Glossary out of the html rendered by StardictRenderer
fn build_glossary(dict_name: &str, ydict: YomitanDict) -> Glossary {
    // Aren't these duplicated in entries?
    let mut alt_map = AltMap::new();
    for entry in &ydict.term_bank_form {
        for def in &entry.definitions {
            let DetailedDefinition::Inflection((from, _tags)) = def else {
                panic!("forms must be made from inflections");
            };
            alt_map
                .entry(from.clone())
                .or_default()
                .push(AltEntry::only_term(entry.term.clone()));
        }
    }

    // We don't need to sort entries it since pangloss does it on write:
    // https://github.com/daxida/pangloss/blob/master/src/formats/stardict/writer.rs#L66
    let entries: Vec<Entry> = ydict
        .into_iter_flat()
        .map(|entry| {
            Entry::new(
                entry.term().to_string(),
                Definition::Html(StardictRenderer::render_entry(&entry).into_string()),
            )
        })
        .collect();

    let mut info = GlossaryInfo::new();
    info.insert("name", dict_name.to_string());
    info.insert("sametypesequence", "h".to_string());

    Glossary {
        entries,
        alt_map,
        info,
        ..Default::default()
    }
}