Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 90 additions & 23 deletions src/flashcards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use std::{
fs,
ops::{Index, IndexMut, Not},
path::Path,
str::FromStr,
rc::Rc,
str::{Chars, FromStr},
};

use crossterm::style::Color;
Expand Down Expand Up @@ -41,6 +42,13 @@ impl Set {
}
}
}

pub fn recall_settings(&self, side: Side) -> &RecallSettings {
match side {
Side::Term => &self.recall_t,
Side::Definition => &self.recall_d,
}
}
}

impl FromStr for Set {
Expand Down Expand Up @@ -97,9 +105,13 @@ impl FromStr for Set {
true
} else {
match line.split_once(':') {
Some(("T", term)) => card[Side::Term].push(trim(term).to_owned()),
Some(("T", term)) => card[Side::Term].push_display(trim(term)),
Some(("D", definition)) => {
card[Side::Definition].push(trim(definition).to_owned())
card[Side::Definition].push_display(trim(definition))
}
Some(("t", term)) => card[Side::Term].push_accepted(trim(term)),
Some(("d", definition)) => {
card[Side::Definition].push_accepted(trim(definition))
}
Some((tag, _)) => errors.push(ParseFlashcardItemError::UnknownTag {
tag: tag.to_owned(),
Expand Down Expand Up @@ -281,10 +293,11 @@ macro_rules! load_set {
};
}

// NOT `Copy` because non-Copy fields may be added in the future
#[derive(Debug, Default, Clone)]
pub struct RecallSettings {
matching: bool,
text: bool,
pub matching: bool,
pub text: bool,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -330,32 +343,92 @@ impl IndexMut<Side> for Flashcard {
}

#[derive(Debug, Clone)]
pub struct FlashcardText(SmallVec<[String; 1]>);
pub struct FlashcardText {
vals: SmallVec<[Rc<str>; 1]>,
num_display: u8,
}

impl FlashcardText {
const fn empty() -> Self {
FlashcardText(SmallVec::new_const())
FlashcardText {
vals: SmallVec::new_const(),
num_display: 0,
}
}

/// Returns true if this is valid
///
/// A flashcard text is valid if it has at least 1 value
fn is_valid(&self) -> bool {
!self.0.is_empty()
self.num_display > 0
}

pub fn display_options(&self) -> &[Rc<str>] {
&self.vals[..self.num_display as usize]
}

pub fn push_display(&mut self, val: impl Into<Rc<str>>) {
self.vals.push(val.into());
self.num_display = self
.num_display
.checked_add(1)
.expect("Flascards cannot have more than 255 values!");
}

pub fn push(&mut self, val: String) {
self.0.push(val);
pub fn push_accepted(&mut self, val: impl Into<Rc<str>>) {
self.vals.push(val.into());
}

pub fn display(&self) -> &str {
self.0.choose(&mut rand::thread_rng()).unwrap()
pub fn display(&self) -> &Rc<str> {
self.display_options()
.choose(&mut rand::thread_rng())
.unwrap()
}

pub fn contains(&self, val: &str, settings: &RecallSettings) -> bool {
fn eq_with_settings(pat: &str, val: &str, settings: &RecallSettings) -> bool {
struct Iter<'a> {
chars_iter: Chars<'a>,
#[allow(dead_code)]
settings: &'a RecallSettings,
}
impl<'a> Iterator for Iter<'a> {
type Item = char;

fn next(&mut self) -> Option<Self::Item> {
self.chars_iter
.by_ref()
.find(|c| !c.is_ascii_whitespace())
.map(|c| c.to_ascii_lowercase())
}
}
Iter {
chars_iter: pat.chars(),
settings,
}
.eq(Iter {
chars_iter: val.chars(),
settings,
})
}
self.vals
.iter()
.any(|pat| eq_with_settings(pat, val, settings))
}
}

impl FlashcardText {
pub fn new(text: String) -> Self {
Self(smallvec![text])
pub fn new(text: impl Into<Rc<str>>) -> Self {
Self {
vals: smallvec![text.into()],
num_display: 0,
}
}
}

impl From<Rc<str>> for FlashcardText {
fn from(s: Rc<str>) -> Self {
Self::new(s)
}
}

Expand All @@ -367,20 +440,14 @@ impl From<String> for FlashcardText {

impl From<&str> for FlashcardText {
fn from(s: &str) -> Self {
Self::new(s.to_owned())
}
}

impl From<&[&str]> for FlashcardText {
fn from(list: &[&str]) -> Self {
Self(list.iter().map(|&s| s.to_owned()).collect())
Self::new(s)
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Side {
Term,
Definition,
Term = 0,
Definition = 1,
}

impl Side {
Expand Down
102 changes: 2 additions & 100 deletions src/input.rs
Original file line number Diff line number Diff line change
@@ -1,100 +1,2 @@
#[macro_export]
macro_rules! up {
() => {
crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Up,
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('w'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('W'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('k'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('K'),
..
})
};
}

#[macro_export]
macro_rules! down {
() => {
crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Down,
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('s'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('S'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('j'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('J'),
..
})
};
}

#[macro_export]
macro_rules! left {
() => {
crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Left,
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('a'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('A'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('h'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('H'),
..
})
};
}

#[macro_export]
macro_rules! right {
() => {
crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Right,
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('d'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('D'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('l'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('L'),
..
})
};
}

#[macro_export]
macro_rules! click {
() => {
crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char(' '),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Enter,
..
})
};
}
pub mod macros;
pub mod text;
100 changes: 100 additions & 0 deletions src/input/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#[macro_export]
macro_rules! up {
() => {
crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Up,
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('w'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('W'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('k'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('K'),
..
})
};
}

#[macro_export]
macro_rules! down {
() => {
crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Down,
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('s'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('S'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('j'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('J'),
..
})
};
}

#[macro_export]
macro_rules! left {
() => {
crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Left,
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('a'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('A'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('h'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('H'),
..
})
};
}

#[macro_export]
macro_rules! right {
() => {
crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Right,
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('d'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('D'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('l'),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char('L'),
..
})
};
}

#[macro_export]
macro_rules! click {
() => {
crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Char(' '),
..
}) | crossterm::event::Event::Key(crossterm::event::KeyEvent {
code: crossterm::event::KeyCode::Enter,
..
})
};
}
Loading