use std::{fmt::Display, fs::read_to_string}; use inline_colorization::*; use quick_xml::de::from_str; use serde::Deserialize; pub fn get(query: &str) -> Option { // TODO Put this in a singleton let file = read_to_string("/usr/local/bible/HebrewStrong.xml").expect("Failed to get the strong xml file. It's expect to be at:\n/usr/local/bible/HebrewString.xml\n\n"); let obj: HebrewStrong = from_str(&file).unwrap(); // Yes, dumb search is ok. Searching for the last element took 2ms obj.entries.into_iter().find(|entry| entry.number.eq(&query)) } #[derive(Deserialize)] pub struct HebrewStrong { #[serde(rename = "$value")] pub entries: Vec, } #[derive(Deserialize, Debug)] pub struct Entry { #[serde(rename = "@id")] pub number: String, w: Word, // TODO find who has multiple notes note: Option>, source: Option, meaning: Option, usage: Option, } impl Display for Entry { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "{color_red}Strong's ID{style_reset}: {}", self.number)?; if let Some(notes) = &self.note { write!(f, "Notes:")?; for note in notes { writeln!(f, "{}", note)?; } } write!(f, "{}", self.w)?; if let Some(i) = &self.source { writeln!(f, "{}", i)?; } if let Some(i) = &self.meaning { writeln!(f, "{}", i)?; } if let Some(i) = &self.usage { writeln!(f, "{}", i)?; } Ok(()) } } #[derive(Deserialize, Debug)] struct Word { #[serde(rename = "@pos")] // TODO this is actaully a link to PartsOfSpeech.xml part_of_speech: Option, #[serde(rename = "@pron")] pronunciation: Option, #[serde(rename = "@xlit")] transliteration: Option, #[serde(rename = "@xlm:lang")] lang: Option, #[serde(rename = "$value")] inner: String, #[serde(rename = "@src")] links_to: Option, } impl Display for Word { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(part_of_speech) = &self.part_of_speech { writeln!(f, "{color_magenta}Part of speech{style_reset}: {}", part_of_speech)?; } if let Some(i) = &self.transliteration { writeln!(f, "{color_green}Transliteration{style_reset}: {}", i)?; } if let Some(i) = &self.lang { writeln!(f, "{color_red}Language{style_reset}: {}", i)?; } writeln!(f, "{color_bright_cyan}Writen{style_reset}: {}", self.inner)?; if let Some(pron) = &self.pronunciation { writeln!(f, "{color_yellow}Pronounciation{style_reset}: {}", pron)?; } if let Some(i) = &self.links_to { writeln!(f, "{color_bright_green}Also see{style_reset}: {}", i)?; } Ok(()) } } #[derive(Deserialize, Debug)] struct Note { #[serde(rename = "$value")] inner: String, } impl Display for Note { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.inner) } } #[derive(Deserialize, Debug)] struct Source { #[serde(rename = "$value")] // Text vs Words make this a vec inner: Option>, } impl Display for Source { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(inner) = &self.inner { // WE ARE LOOPING // !! Don't use writeln write!(f, "{color_bright_green}Source{style_reset}: ")?; for i in inner { match i { MixedText::Word(word) => { if let Some(i) = &word.links_to { write!(f, "{style_bold} (See: {}){style_reset}", i)?; } write!(f, "{color_bright_white} {} {style_reset}", word.inner)?; }, _ => write!(f, "{}", i)?, } } } Ok(()) } } #[derive(Deserialize, Debug)] struct Meaning { #[serde(rename = "$value")] inner: Vec, } impl Display for Meaning { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{color_cyan}Meaning:{style_reset}")?; for i in &self.inner { write!(f, "{}", i)?; } Ok(()) } } #[derive(Deserialize, Debug)] struct Usage { #[serde(rename = "$value")] inner: Vec, } impl Display for Usage { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let new = self.inner.join(" "); write!(f, "{color_bright_magenta}Usage{style_reset}: {new}") } } #[derive(Deserialize, Debug)] enum MixedText { #[serde(rename = "w")] Word(Word), #[serde(rename = "$text")] Text(String), #[serde(rename = "def")] /// The actual definition, as opposed to the supporting `MixedText::Text`, which is just /// supporting text elements. Definition(String), #[serde(rename = "note")] Note(Note), } impl Display for MixedText { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { MixedText::Word(word) => write!(f, "{}", word), MixedText::Text(text) => write!(f, "{}", text), MixedText::Definition(def) => write!(f, " {style_bold}{}{style_reset} ", def), MixedText::Note(note) => write!(f, "{}", note), } } }