use serde::{Deserialize, Serialize};
use crate::{answer::Mode, card::Card};
#[derive(
Clone,
Copy,
Debug,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
clap::ValueEnum,
)]
#[serde(rename_all = "lowercase")]
#[clap(rename_all = "lowercase")]
pub enum Depth {
Recognize,
#[default]
Recall,
Reconstruct,
}
pub fn depth_name(depth: Depth) -> &'static str {
match depth {
Depth::Recognize => "recognize",
Depth::Recall => "recall",
Depth::Reconstruct => "reconstruct",
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, Serialize, Deserialize, clap::ValueEnum)]
#[serde(rename_all = "lowercase")]
pub enum Reveal {
#[default]
Flip,
Cloze,
Line,
}
fn answer_is_atomic(card: &Card) -> bool {
card.back.len() == 1
}
pub fn check_for(reveal: Reveal, depth: Depth, card: &Card) -> Mode {
match depth {
Depth::Recognize => Mode::Choice,
Depth::Recall => match reveal {
Reveal::Flip | Reveal::Cloze => Mode::Flip,
Reveal::Line => Mode::LineByLine,
},
Depth::Reconstruct => match reveal {
Reveal::Cloze => Mode::Typing,
Reveal::Line => Mode::TypeLine,
Reveal::Flip => {
if answer_is_atomic(card) {
Mode::Typing
} else {
Mode::Explain
}
}
},
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{answer::Mode, parser};
fn card(back: &str) -> crate::card::Card {
let text = format!("# q\n{back}");
parser::parse_str("t", &text).unwrap().remove(0)
}
#[test]
fn recognize_depth_always_renders_a_choice_check() {
for reveal in [Reveal::Flip, Reveal::Cloze, Reveal::Line] {
assert_eq!(
Mode::Choice,
check_for(reveal, Depth::Recognize, &card("a"))
);
}
}
#[test]
fn recall_depth_maps_reveal_to_its_self_graded_check() {
assert_eq!(
Mode::Flip,
check_for(Reveal::Flip, Depth::Recall, &card("a"))
);
assert_eq!(
Mode::Flip,
check_for(Reveal::Cloze, Depth::Recall, &card("a"))
);
assert_eq!(
Mode::LineByLine,
check_for(Reveal::Line, Depth::Recall, &card("a"))
);
}
#[test]
fn reconstruct_depth_types_atoms_ticks_rich_and_types_lines() {
assert_eq!(
Mode::Typing,
check_for(Reveal::Flip, Depth::Reconstruct, &card("a"))
);
assert_eq!(
Mode::Explain,
check_for(Reveal::Flip, Depth::Reconstruct, &card("a\n b"))
);
assert_eq!(
Mode::Typing,
check_for(Reveal::Cloze, Depth::Reconstruct, &card("a {{b}}"))
);
assert_eq!(
Mode::TypeLine,
check_for(Reveal::Line, Depth::Reconstruct, &card("a\n b"))
);
}
#[test]
fn depth_serializes_lowercase_and_defaults_to_recall() {
assert_eq!(Depth::default(), Depth::Recall);
assert_eq!(
"\"recognize\"",
serde_json::to_string(&Depth::Recognize).unwrap()
);
}
}