#![doc = simple_mermaid::mermaid!("../diagrams/input_handler_flow.mmd")]
use crate::buffer::Buffer;
use crate::{CharacterResult, State};
#[derive(Debug, Clone)]
pub struct InputHandler {
input: Vec<char>,
}
impl InputHandler {
pub fn new() -> Self {
Self { input: vec![] }
}
pub fn is_input_empty(&self) -> bool {
self.input.is_empty()
}
pub fn input_len(&self) -> usize {
self.input.len()
}
pub fn is_fully_typed(&self, text_len: usize) -> bool {
self.input.len() == text_len
}
pub fn process_input(
&mut self,
input: Option<char>,
text_buffer: &mut Buffer,
) -> Option<(char, CharacterResult)> {
if self.is_fully_typed(text_buffer.text_len()) {
return None;
}
input
.and_then(|char| {
self.add_input(char, text_buffer)
.map(|result| (char, result))
})
.or_else(|| self.delete_input(text_buffer))
}
fn add_input(&mut self, input: char, text_buffer: &mut Buffer) -> Option<CharacterResult> {
let index = self.input.len();
let character = text_buffer.get_character_mut(index)?;
let result;
let new_state;
let prev_state = character.state;
if character.char != input {
new_state = State::Wrong;
result = CharacterResult::Wrong;
} else {
result = match prev_state {
State::None => {
new_state = State::Correct;
CharacterResult::Correct
}
State::WasWrong => {
new_state = State::Corrected;
CharacterResult::Corrected
}
State::WasCorrected => {
new_state = State::Corrected;
CharacterResult::Correct
}
State::WasCorrect => {
new_state = State::Correct;
CharacterResult::Correct
}
_ => unreachable!("Tried to add to already typed character!"),
}
}
self.input.push(input);
character.state = new_state;
text_buffer.update_word_state_incrementally(index, new_state);
Some(result)
}
fn delete_input(&mut self, text_buffer: &mut Buffer) -> Option<(char, CharacterResult)> {
let deleted = self.input.pop()?;
let index = self.input.len();
let character = text_buffer
.get_character_mut(index)
.expect("Failed to get current character");
let prev_state = character.state;
match prev_state {
State::Wrong => character.state = State::WasWrong,
State::Corrected => character.state = State::WasCorrected,
State::Correct => character.state = State::WasCorrect,
_ => unreachable!("Tried to delete a non-typed character!"),
}
let result = CharacterResult::Deleted(prev_state);
let character_state = character.state;
text_buffer.update_word_state_incrementally(index, character_state);
Some((deleted, result))
}
}
impl Default for InputHandler {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::buffer::Buffer;
#[test]
fn test_input_handler_basic() {
let mut text_buffer = Buffer::new("abc").unwrap();
let mut input_handler = InputHandler::new();
let result = input_handler
.process_input(Some('a'), &mut text_buffer)
.unwrap();
assert_eq!(result.0, 'a');
assert!(matches!(result.1, CharacterResult::Correct));
assert_eq!(input_handler.input_len(), 1);
assert!(!input_handler.is_input_empty());
let result = input_handler
.process_input(Some('x'), &mut text_buffer)
.unwrap();
assert_eq!(result.0, 'x');
assert!(matches!(result.1, CharacterResult::Wrong));
assert_eq!(input_handler.input_len(), 2);
let result = input_handler.process_input(None, &mut text_buffer).unwrap();
assert_eq!(result.0, 'x');
assert!(matches!(result.1, CharacterResult::Deleted(_)));
assert_eq!(input_handler.input_len(), 1);
let result = input_handler
.process_input(Some('b'), &mut text_buffer)
.unwrap();
assert_eq!(result.0, 'b');
assert!(matches!(result.1, CharacterResult::Corrected));
assert_eq!(input_handler.input_len(), 2);
let result = input_handler
.process_input(Some('c'), &mut text_buffer)
.unwrap();
assert_eq!(result.0, 'c');
assert!(matches!(result.1, CharacterResult::Correct));
assert_eq!(input_handler.input_len(), 3);
assert!(input_handler.is_fully_typed(text_buffer.text_len()));
assert!(
input_handler
.process_input(Some('d'), &mut text_buffer)
.is_none()
);
}
#[test]
fn test_input_handler_deletion() {
let mut text_buffer = Buffer::new("abc").unwrap();
let mut input_handler = InputHandler::new();
assert!(
input_handler
.process_input(None, &mut text_buffer)
.is_none()
);
input_handler
.process_input(Some('a'), &mut text_buffer)
.unwrap();
assert_eq!(input_handler.input_len(), 1);
let result = input_handler.process_input(None, &mut text_buffer).unwrap();
assert_eq!(result.0, 'a');
assert!(matches!(result.1, CharacterResult::Deleted(_)));
assert_eq!(input_handler.input_len(), 0);
}
#[test]
fn test_input_handler_correction_sequence() {
let mut text_buffer = Buffer::new("abc").unwrap();
let mut input_handler = InputHandler::new();
input_handler
.process_input(Some('x'), &mut text_buffer)
.unwrap(); input_handler.process_input(None, &mut text_buffer).unwrap(); let result = input_handler
.process_input(Some('a'), &mut text_buffer)
.unwrap();
assert_eq!(result.0, 'a');
assert!(matches!(result.1, CharacterResult::Corrected));
}
}