deckster 0.2.1

Tui to study flashcards in the terminal
Documentation
mod sm2;
mod records;
mod slide;
mod events;
mod cards;
pub mod errors;

use records::*;
use slide::Slide;
use std::io;
use termion::raw::IntoRawMode;
use termion::event::Key;
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::layout::{Constraint,Direction,Layout};
use events::Event;
use errors::Res;

const DEFAULT: usize = 20;

pub fn start_tui(file : &str, num: Option<usize>) -> Res<()> {
    let stdout = io::stdout().into_raw_mode()?;
    let backend = TermionBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    let events = events::setup_events();
    let records = Records::read_file(file)?.records();

    let num = num.unwrap_or(DEFAULT);
    let mut cards = cards::Cards::from(records).select(num);

    terminal.clear()?;

    while let Some(_) = cards.next() {
        let record = cards.current_record();
        let mut slide = Slide::default().record(record);

        let mut exit_called = false;
        let mut exit = || exit_called = true;

        while let Some(step) = slide.step() {
            let final_step = step == 2;
            let record = slide.clone();

            terminal.draw(|f| {
                let h2 = 3u16;
                let h1 = f.size().height - h2;

                let section = Layout::default()
                    .direction(Direction::Vertical)
                    .constraints(
                        [
                            Constraint::Length(h1),
                            Constraint::Length(h2),
                        ]
                    ).split(f.size());

                f.render_widget(record.clone(),section[0]);
                f.render_widget(cards.status(),section[1]);
            })?;

            match events.recv().unwrap() {
                Event::Refresh => (),
                Event::Key(key) => match key {
                    Key::Char(' ') =>  if !final_step { slide.cont() },
                    Key::Char('\n') => if final_step { slide.cont() },
                    Key::Char('l') | Key::Right => if final_step {slide.next()},
                    Key::Char('h') | Key::Left =>  if final_step {slide.prev()},
                    Key::Char('q') | Key::Esc => { exit(); break },
                    Key::Ctrl('c') | Key::Ctrl('d') => { exit(); break },
                    _ => (),
                },
            };
        }
        if exit_called { break }

        let rating = slide.rating();
        cards.review_current_card(rating);
    };

    let records = cards.records();
    let records = Records::from(records);
    records.write_to_file(file)?;
    terminal.clear()?;
    Ok(())
}

pub fn generate_sample() -> Res<()> {
    let sample =
r#"
# Structure each new card in the format below.
# Deckster will generate additional metadata for each
# card and store it in this file. Avoid editing
# the metadata.
#
# Uncomment the block below to begin.
#
# [[card]]
# question = 'question 1'
# answer = 'answer 1'
"#;
    println!("{}",sample);
    Ok(())
}