diff options
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | src/gui/message.rs | 7 | ||||
-rw-r--r-- | src/gui/mod.rs | 9 | ||||
-rw-r--r-- | src/gui/question.rs | 95 |
4 files changed, 79 insertions, 36 deletions
@@ -1,7 +1,7 @@ # Getting started ```bash -nix develop --command bin/watch.sh +nix develop --command bin/dev-server.sh ``` # Screenshot @@ -22,7 +22,7 @@ Cards are created from a plain text `./deck` file: - good moorning : bonjour - alternative 1 | alternative 2 : choix 1 | choix 2 -- cat (indication) : chat +- cat (indication) : chat [ʃa] ``` # Backlog diff --git a/src/gui/message.rs b/src/gui/message.rs index f0d826a..61f57ba 100644 --- a/src/gui/message.rs +++ b/src/gui/message.rs @@ -1,6 +1,6 @@ use crate::gui::util; -use crossterm::event::{self, Event, KeyCode, KeyModifiers}; use anyhow::Result; +use crossterm::event::{self, Event, KeyCode, KeyModifiers}; use tui::{ backend::Backend, layout::{Alignment, Constraint, Direction, Layout}, @@ -32,7 +32,10 @@ pub fn show<B: Backend>( if wait { if let Event::Key(key) = event::read()? { - if key.code == KeyCode::Char('q') || key.code == KeyCode::Char('c') && key.modifiers.contains(KeyModifiers::CONTROL) { + if key.code == KeyCode::Char('q') + || key.code == KeyCode::Char('c') + && key.modifiers.contains(KeyModifiers::CONTROL) + { break; } } diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 1053de1..b500706 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -4,10 +4,10 @@ pub mod util; use crate::{db, space_repetition, util::time}; use anyhow::Result; +use crossterm::terminal; use rusqlite::Connection; use std::io::Stdout; use tui::{backend::CrosstermBackend, Terminal}; -use crossterm::{terminal}; pub type Term = Terminal<CrosstermBackend<Stdout>>; @@ -36,7 +36,12 @@ pub fn start( loop { let now = time::seconds_since_unix_epoch()?; - let title = title(deck_name, answers, db::count_available(conn).unwrap_or(0), hide_progress); + let title = title( + deck_name, + answers, + db::count_available(conn).unwrap_or(0), + hide_progress, + ); match db::pick_random_ready(conn) { Some(card) => match question::ask(term, &title, &card)? { diff --git a/src/gui/question.rs b/src/gui/question.rs index abb8fd7..1c44272 100644 --- a/src/gui/question.rs +++ b/src/gui/question.rs @@ -29,11 +29,7 @@ pub enum Response { Answered { difficulty: Difficulty }, } -pub fn ask<B: Backend>( - terminal: &mut Terminal<B>, - title: &str, - card: &Card, -) -> Result<Response> { +pub fn ask<B: Backend>(terminal: &mut Terminal<B>, title: &str, card: &Card) -> Result<Response> { let mut state = State { input: String::new(), answer: Answer::Write, @@ -81,10 +77,11 @@ pub fn ask<B: Backend>( .style(match state.answer { Answer::Write => Style::default(), Answer::Difficulty { difficulty: _ } => { - if is_correct(&state.input, &card.responses) { - Style::default().fg(Color::Green) - } else { - Style::default().fg(Color::Red) + match check_response(&state.input, &card.responses) { + CheckResponse::Correct { phonetics: _ } => { + Style::default().fg(Color::Green) + } + CheckResponse::Incorrect => Style::default().fg(Color::Red), } } }) @@ -97,12 +94,17 @@ pub fn ask<B: Backend>( difficulty: selected, } = state.answer { - if !is_correct(&state.input, &card.responses) { - let paragraph = Paragraph::new(util::center_vertically( - chunks[3], - &serialization::words_to_line(&card.responses), - )) - .alignment(Alignment::Center); + let maybe_indication: Option<String> = + match check_response(&state.input, &card.responses) { + CheckResponse::Correct { phonetics } => phonetics, + CheckResponse::Incorrect => { + Some(serialization::words_to_line(&card.responses)) + } + }; + + if let Some(indication) = maybe_indication { + let paragraph = Paragraph::new(util::center_vertically(chunks[3], &indication)) + .alignment(Alignment::Center); f.render_widget(paragraph, chunks[3]); }; @@ -138,10 +140,9 @@ pub fn ask<B: Backend>( match state.answer { Answer::Write => match key.code { KeyCode::Enter => { - let difficulty = if is_correct(&state.input, &card.responses) { - Difficulty::Good - } else { - Difficulty::Again + let difficulty = match check_response(&state.input, &card.responses) { + CheckResponse::Correct { phonetics: _ } => Difficulty::Good, + CheckResponse::Incorrect => Difficulty::Again, }; state.answer = Answer::Difficulty { difficulty } } @@ -150,7 +151,8 @@ pub fn ask<B: Backend>( if c == 'u' { state.input.clear(); } else if c == 'w' { - let mut words = state.input.split_whitespace().collect::<Vec<&str>>(); + let mut words = + state.input.split_whitespace().collect::<Vec<&str>>(); if !words.is_empty() { words.truncate(words.len() - 1); let joined_words = words.join(" "); @@ -162,7 +164,9 @@ pub fn ask<B: Backend>( } } else { state.input.push(c); - if is_correct(&state.input, &card.responses) { + if let CheckResponse::Correct { phonetics: _ } = + check_response(&state.input, &card.responses) + { state.answer = Answer::Difficulty { difficulty: Difficulty::Good, } @@ -205,19 +209,50 @@ pub fn ask<B: Backend>( } } -fn is_correct(input: &str, responses: &[String]) -> bool { - // Remove whitespaces - let input = input +enum CheckResponse { + Incorrect, + Correct { phonetics: Option<String> }, +} + +fn check_response(input: &str, responses: &[String]) -> CheckResponse { + let input = remove_whitespaces(input); + + responses + .iter() + .find(|r| remove_indications_and_phonetics(r) == input) + .map(|r| CheckResponse::Correct { + phonetics: extract_phonetics(r), + }) + .unwrap_or(CheckResponse::Incorrect) +} + +fn remove_whitespaces(input: &str) -> String { + input .split_whitespace() .map(|word| word.trim()) .collect::<Vec<&str>>() - .join(" "); + .join(" ") +} - responses - .iter() - .map(|r| r.split('(').collect::<Vec<&str>>()[0].trim()) - .map(|r| r.split('[').collect::<Vec<&str>>()[0].trim()) - .any(|x| x == input) +fn remove_indications_and_phonetics(response: &str) -> &str { + response + .split(|c| c == '(' || c == '[') + .collect::<Vec<&str>>()[0] + .trim() +} + +fn extract_phonetics(response: &str) -> Option<String> { + let s1 = response.split('[').collect::<Vec<&str>>(); + if s1.len() == 2 { + let s2 = s1[1].split(']').collect::<Vec<&str>>(); + if s2.len() > 1 { + Some(format!("[{}]", s2[0])) + } else { + None + } + } else { + None + } } fn relative_element<T: Clone + PartialEq>(xs: &[T], x: &T, ri: i32) -> Option<T> { |