use std::collections::{BTreeMap, HashSet}; #[derive(Clone, Copy)] pub enum SfxMode { Off, On, } struct Translation<'a> { find: &'a str, replacement: &'a str, } #[derive(Clone)] pub struct Variant<'v> { keep_delim: &'v str, remove_delims: HashSet<&'v str>, } impl<'v> Variant<'v> { pub fn ignores(&self) -> &HashSet<&str> { &self.remove_delims } } pub struct VariantList<'v> { all_delims: HashSet<&'v str>, variants: BTreeMap<&'v str, Variant<'v>>, } impl<'v> VariantList<'v> { fn new() -> Self { VariantList { all_delims: HashSet::new(), variants: BTreeMap::new(), } } fn finish(mut self) -> Self { for (_, v) in self.variants.iter_mut() { v.remove_delims = self.all_delims.clone(); v.remove_delims.remove(v.keep_delim); } if self.variants.is_empty() { self.variants.insert( "_default_", Variant { keep_delim: "", remove_delims: self.all_delims.clone(), }, ); } self } pub fn get(&self, name: &str) -> Option<&Variant> { self.variants.get(name) } } pub fn replace_chars(input: &str) -> String { let trs: Vec> = input .lines() .filter_map(|line| { line.strip_prefix("#REPLACE") .and_then(|l| l.trim().rsplit_once(' ')) .and_then(|(first, second)| { let length = std::cmp::min(first.len(), second.len()); Some(Translation { find: &first[0..length], replacement: &second[0..length], }) }) }) .collect(); let mut new = input.to_string(); for tr in trs { new = new.replace(tr.find, tr.replacement); } new } pub fn get_variants<'a>(input: &'a str, sfx_mode: SfxMode) -> VariantList<'a> { input .lines() .fold(VariantList::new(), |mut state, line| { if let Some(l) = line.strip_prefix("#SFXV") { if let Some((first, second)) = l.trim().rsplit_once(' ') { use SfxMode::*; match sfx_mode { Off => state.all_delims.insert(first), On => state.all_delims.insert(second), }; } } else if let Some(l) = line.strip_prefix("#VARIANT") { let (first, second) = { let rest = l.trim(); if let Some((f, s)) = rest.rsplit_once(' ') { (f, s) } else { (rest, "_default_") } }; state.all_delims.insert(first); if state.variants.len() == 0 && second != "_default_" { state.variants.insert( "_default_", Variant { keep_delim: first, remove_delims: HashSet::new(), }, ); } state.variants.insert( second, Variant { keep_delim: first, remove_delims: HashSet::new(), }, ); } state }) .finish() }