mod text;
mod verdict;
pub use text::{usage, version};
pub use verdict::{Stream, Verdict};
#[derive(Debug)]
pub enum Decided {
Say(Verdict),
Entries,
Window,
Start { address: String, goal: String },
Enroll {
workspace: String,
name: String,
grade: String,
},
Ask(serde_json::Value),
Fanned(serde_json::Value),
}
pub fn run(args: Vec<String>) -> Decided {
let words: Vec<&str> = args.iter().map(String::as_str).collect();
match words.as_slice() {
["entries"] => Decided::Entries,
["ask", envelope] => ask(envelope),
["help" | "--help" | "-h"] => Decided::Say(Verdict::ok(usage())),
["help", verb] => Decided::Say(match crate::verbs::help::page(verb) {
Ok(page) => Verdict::ok(page),
Err(refusal) => Verdict::refused(refusal),
}),
["--version" | "-V"] => Decided::Say(Verdict::ok(version())),
["start", address, goal] => Decided::Start {
address: (*address).to_owned(),
goal: (*goal).to_owned(),
},
["enroll", workspace, name, grade] => enroll(workspace, name, grade),
[] => Decided::Window,
[word, arguments @ ..] => typed(word, arguments),
}
}
fn ask(text: &str) -> Decided {
match crate::envelope::parse(text) {
Ok(envelope) => Decided::Ask(envelope),
Err(refusal) => Decided::Say(Verdict::refused(refusal)),
}
}
fn enroll(workspace: &str, name: &str, grade: &str) -> Decided {
let words = crate::ui::Grade::both();
let Some(held) = words.iter().find(|known| known.word() == grade) else {
return Decided::Say(Verdict::refused(format!(
"unknown grade {grade:?} — `lernie enroll` takes {}",
words
.iter()
.map(|known| format!("{:?}", known.word()))
.collect::<Vec<String>>()
.join(" or ")
)));
};
Decided::Enroll {
workspace: workspace.to_owned(),
name: name.to_owned(),
grade: held.word(),
}
}
fn typed(word: &str, arguments: &[&str]) -> Decided {
if let Some(verb) = crate::verbs::find(word) {
return match verb.envelope(arguments.iter().map(|a| (*a).to_owned()).collect()) {
Ok(envelope) if verb.addresses_a_workspace() => Decided::Ask(envelope),
Ok(envelope) => Decided::Fanned(envelope),
Err(refusal) => Decided::Say(Verdict::refused(refusal)),
};
}
if let Some(door) = crate::verbs::doors::find(word) {
return Decided::Say(Verdict::refused(door.refused(arguments.len())));
}
Decided::Say(Verdict::refused(format!(
"unrecognised argument: {}",
std::iter::once(word)
.chain(arguments.iter().copied())
.collect::<Vec<&str>>()
.join(" ")
)))
}
#[cfg(test)]
mod tests;