diff options
Diffstat (limited to 'crates/cli')
| -rw-r--r-- | crates/cli/src/words.rs | 273 |
1 files changed, 177 insertions, 96 deletions
diff --git a/crates/cli/src/words.rs b/crates/cli/src/words.rs index 40f3f26..953760a 100644 --- a/crates/cli/src/words.rs +++ b/crates/cli/src/words.rs @@ -4,7 +4,7 @@ use crate::locale::current_locale; use inquire::{Confirm, Editor, MultiSelect, Select, Text}; use mihi::{ adverb, comparative, joint_related_words, select_related_words, select_tags_for, superlative, - Category, Gender, Language, RelationKind, Word, + Category, Conjugation, Declension, Gender, Language, RelationKind, Word, }; use std::vec::IntoIter; @@ -98,7 +98,7 @@ fn get_initial_guess(value: &str) -> Word { return Word::from( first[0..first.len() - 1].to_string(), Category::Noun, - Some(1), + Some(Declension::First), None, Gender::Feminine, "a".to_string(), @@ -107,7 +107,7 @@ fn get_initial_guess(value: &str) -> Word { return Word::from( first[0..first.len() - 2].to_string(), Category::Noun, - Some(2), + Some(Declension::Second), None, Gender::Masculine, "us".to_string(), @@ -116,7 +116,7 @@ fn get_initial_guess(value: &str) -> Word { return Word::from( first[0..first.len() - 2].to_string(), Category::Noun, - Some(2), + Some(Declension::Second), None, Gender::Neuter, "um".to_string(), @@ -125,7 +125,7 @@ fn get_initial_guess(value: &str) -> Word { return Word::from( first[0..first.len() - 2].to_string(), Category::Noun, - Some(4), + Some(Declension::Fourth), None, Gender::Masculine, "fus".to_string(), @@ -134,7 +134,7 @@ fn get_initial_guess(value: &str) -> Word { return Word::from( first[0..first.len() - 1].to_string(), Category::Noun, - Some(4), + Some(Declension::Fourth), None, Gender::Masculine, "fus".to_string(), @@ -143,7 +143,7 @@ fn get_initial_guess(value: &str) -> Word { return Word::from( first[0..first.len() - 3].to_string(), Category::Noun, - Some(5), + Some(Declension::Fifth), None, Gender::Masculine, "ies".to_string(), @@ -152,7 +152,7 @@ fn get_initial_guess(value: &str) -> Word { return Word::from( first[0..first.len() - 2].to_string(), Category::Noun, - Some(5), + Some(Declension::Fifth), None, Gender::Masculine, "es".to_string(), @@ -161,7 +161,7 @@ fn get_initial_guess(value: &str) -> Word { return Word::from( second[0..second.len() - 2].to_string(), Category::Noun, - Some(3), + Some(Declension::Third), None, Gender::Masculine, "is".to_string(), @@ -207,6 +207,62 @@ fn get_translated<'a>(word: &'a Word, key: &'a str) -> Result<&'a String, String } } +fn prompt_declension(cat: &Category, declension: Declension) -> Result<Declension, String> { + let options; + let idx; + + match cat { + Category::Noun => { + options = vec![ + Declension::First, + Declension::Second, + Declension::Third, + Declension::Fourth, + Declension::Fifth, + ]; + idx = declension as usize - 1; + } + Category::Adjective => { + options = vec![Declension::First, Declension::Third]; + idx = if matches!(declension, Declension::Third) { + 1 + } else { + 0 + }; + } + _ => panic!("bad parameter"), + } + + let Ok(result) = Select::new("Declension:", options) + .with_starting_cursor(idx) + .prompt() + else { + return Err("abort!".to_string()); + }; + + Ok(result) +} + +fn prompt_conjugation(conjugation: Conjugation) -> Result<Conjugation, String> { + let options = vec![ + Conjugation::First, + Conjugation::Second, + Conjugation::Third, + Conjugation::ThirdIo, + Conjugation::Fourth, + ]; + let idx = conjugation as usize - 1; + + let Ok(result) = Select::new("Conjugation:", options) + .with_starting_cursor(idx) + .prompt() + else { + return Err("abort!".to_string()); + }; + + Ok(result) +} + // Interactively ask the user to provide information for a word by the given // `enunciated`. The default values will be based on the given `word` parameter. fn ask_for_word_based_on(enunciated: String, word: Word) -> Result<Word, String> { @@ -257,29 +313,68 @@ fn ask_for_word_based_on(enunciated: String, word: Word) -> Result<Word, String> _ => Gender::None, }; - let inflection_id = match category { - Category::Noun | Category::Adjective | Category::Verb => { - let Ok(inflection) = Text::new("Inflection:") - .with_initial_value(word.inflection_id().unwrap_or(0).to_string().as_str()) - .prompt() - else { - return Err("abort!".to_string()); - }; - let Ok(inflection_id) = inflection.parse::<isize>() else { - return Err(format!("bad value for inflection ID '{inflection}'")); - }; - Some(inflection_id) + let declension; + let conjugation; + match category { + Category::Noun | Category::Adjective => { + declension = Some(prompt_declension( + &category, + word.declension.clone().unwrap_or(Declension::First), + )?); + conjugation = None; } - _ => None, - }; + Category::Verb => { + declension = None; + conjugation = Some(prompt_conjugation( + word.conjugation.clone().unwrap_or(Conjugation::First), + )?); + } + _ => { + declension = None; + conjugation = None; + } + } - // TODO: refine guess once the inflection is known: select from possible values. let kind = match category { - Category::Noun | Category::Adjective => { - let Ok(kind) = Text::new("Kind:").with_initial_value(&word.kind).prompt() else { - return Err("abort!".to_string()); + Category::Noun => { + let options = match declension { + Some(Declension::First) => vec!["a"], + Some(Declension::Second) => vec!["us", "um", "ius", "er/ir"], + Some(Declension::Third) => vec![ + "is", + "istem", + "pureistem", + "one", + "onenonistem", + "two", + "three", + "visvis", + "sussuis", + "bosbovis", + "iuppiteriovis", + ], + Some(Declension::Fourth) => vec!["fus"], + Some(Declension::Fifth) => vec!["ies", "es"], + _ => panic!("shouldn't be here :D"), }; - kind.trim().to_string() + if options.len() == 1 { + options.first().unwrap().to_string() + } else { + match Select::new("Kind:", options).prompt() { + Ok(kind) => kind.to_string(), + Err(_) => return Err("abort!".to_string()), + } + } + } + Category::Adjective => { + let options = match declension { + Some(Declension::First) => vec!["us", "er/ir"], + _ => vec!["one", "onenonistem", "two", "three"], + }; + match Select::new("Kind:", options).prompt() { + Ok(kind) => kind.to_string(), + Err(_) => return Err("abort!".to_string()), + } } Category::Verb => String::from("verb"), _ => String::from("-"), @@ -316,10 +411,7 @@ fn ask_for_word_based_on(enunciated: String, word: Word) -> Result<Word, String> return Err("abort!".to_string()); }; let Ok(weight) = raw_weight.parse::<isize>() else { - return Err(format!( - "bad value for inflection ID '{}'", - inflection_id.unwrap_or(0) - )); + return Err("bad value".to_string()); }; if weight > 10 { return Err(format!( @@ -355,13 +447,13 @@ fn ask_for_word_based_on(enunciated: String, word: Word) -> Result<Word, String> enunciated, particle, language: Language::Latin, - declension_id: if matches!(category, Category::Verb) { + declension: if matches!(category, Category::Verb) { None } else { - inflection_id + declension }, - conjugation_id: if matches!(category, Category::Verb) { - inflection_id + conjugation: if matches!(category, Category::Verb) { + conjugation } else { None }, @@ -762,50 +854,52 @@ fn edit(mut args: IntoIter<String>) -> i32 { } } -// Returns a string with a more human-readable declension kind. -fn humanize_kind(kind: &str) -> &str { +// Returns a string with a more human-readable declension kind. If the kind is +// self-explanatory, then None is returned (e.g. "a" is the only kind for the +// first declension, so it's redundant). +fn humanize_kind(kind: &str) -> Option<&str> { match kind { // Noun - "a" => "-a", - "us" => "-us", - "er/ir" => "-er/-ir", - "um" => "-um", - "ius" => "-ius; like 'fīlius'", - "is" => "-is", - "istem" => "i-stem; '-i-' also in the genitive plural", - "pureistem" => "pure i-stem; '-i-' also in the ablative singular", - "visvis" => "irregular 'vīs, vīs'", - "sussuis" => "irregular 'sūs, suis'", - "bosbovis" => "irregular 'bōs, bovis'", - "iuppiteriovis" => "irregular 'Iuppiter, Iovis'", - "fus" => "-u-", - "domusdomus" => "irregular 'domus, domūs/domī'", - "ies" => "-iēs; like 'diēs, diēī'", - "es" => "-ēs; like 'rēs, reī'", - "indeclinable" => "indeclinable", + "a" => None, + "us" => Some("regular -us"), + "er/ir" => Some("-er/-ir"), + "um" => Some("neuter -um"), + "ius" => Some("-ius; like 'fīlius'"), + "is" => Some("regular -is"), + "istem" => Some("i-stem; '-i-' also in the genitive plural"), + "pureistem" => Some("pure i-stem; '-i-' also in the ablative singular"), + "visvis" => Some("irregular 'vīs, vīs'"), + "sussuis" => Some("irregular 'sūs, suis'"), + "bosbovis" => Some("irregular 'bōs, bovis'"), + "iuppiteriovis" => Some("irregular 'Iuppiter, Iovis'"), + "fus" => None, + "domusdomus" => Some("irregular 'domus, domūs/domī'"), + "ies" => Some("-iēs; like 'diēs, diēī'"), + "es" => Some("-ēs; like 'rēs, reī'"), + "indeclinable" => Some("indeclinable"), // Adjective - "one" => "one termination adjective", - "onenonistem" => "one termination adjective; non i-stem like 'melior, melius'", - "two" => "two termination adjective", - "three" => "three termination adjective", - "unusnauta" => "'ūnus nauta' like 'ūnus, ūna, ūnum'", - "unusnautaer/ir" => "'ūnus nauta' like 'neuter, neutra, neutrum'", - "duo" => "number 'duo, duae, duo'", - "tres" => "number 'trēs, trēs, tria'", - "mille" => "number 'mīlle, mīlle'", + "one" => Some("one termination adjective"), + "onenonistem" => Some("one termination adjective; non i-stem like 'melior, melius'"), + "two" => Some("two termination adjective"), + "three" => Some("three termination adjective"), + "unusnauta" => Some("'ūnus nauta' like 'ūnus, ūna, ūnum'"), + "unusnautaer/ir" => Some("'ūnus nauta' like 'neuter, neutra, neutrum'"), + "duo" => Some("number 'duo, duae, duo'"), + "tres" => Some("number 'trēs, trēs, tria'"), + "mille" => Some("number 'mīlle, mīlle'"), // Others - "egonos" => "'ego, nōs'", - "demonstrative-weak" => "weak demonstrative", - "demonstrative-proximal" => "proximal demonstrative", - "demonstrative-distal" => "distal demonstrative", - "demonstrative-medial" => "medial demonstrative", - "demonstrative-idem" => "'īdem, eadem, idem' demonstrative", - "tuvos" => "'tū, vōs'", - "sesui" => "'sē, suī'", - - _ => kind, + "egonos" => Some("'ego, nōs'"), + "demonstrative-weak" => Some("weak demonstrative"), + "demonstrative-proximal" => Some("proximal demonstrative"), + "demonstrative-distal" => Some("distal demonstrative"), + "demonstrative-medial" => Some("medial demonstrative"), + "demonstrative-idem" => Some("'īdem, eadem, idem' demonstrative"), + "tuvos" => Some("'tū, vōs'"), + "sesui" => Some("'sē, suī'"), + + _ => Some(kind), } } @@ -868,35 +962,22 @@ fn title_for_word(word: &Word) -> String { format!("{}; {})", s, flags) } -fn humanize_conjugation(id: isize) -> String { - match id { - 1 => "1st (ā-stems)", - 2 => "2nd (ē-stems)", - 3 => "3rd (ĕ-stems)", - 4 => "3rd (-iō variants)", - 5 => "4th (ī-stems)", - _ => panic!("bad conjugation id {id}"), - } - .to_string() -} - fn show_info(word: Word) -> Result<(), String> { // Title. println!("Word: {}", title_for_word(&word)); // Conjugation, declension + kind. - match word.conjugation_id { - Some(id) => println!("Conjugation: {}", humanize_conjugation(id)), + match word.conjugation { + Some(ref conjugation) => println!("Conjugation: {}", conjugation), None => { - if let Some(did) = word.declension_id { - if did > 5 { - println!("Declension: {}", humanize_kind(&word.kind)); + if let Some(ref d) = word.declension { + if matches!(d, Declension::Other) { + println!("Declension: {}.", humanize_kind(&word.kind).unwrap_or("-")); } else { - println!( - "Declension: {} ({})", - word.declension_id.unwrap(), - humanize_kind(&word.kind) - ); + match humanize_kind(&word.kind) { + Some(k) => println!("Declension: {}; kind: {}.", d, k), + None => println!("Declension: {}", d), + } } } } |
