cyndikator 0.2.2

A cli rss reader
use super::{Action, Mode, Position, ScrollUnit};
use crossterm::{
    event::{KeyCode, KeyEvent},
    Result,
};

pub struct Norm {
    mag: String,
}

impl Default for Norm {
    fn default() -> Norm {
        let mag = String::with_capacity(16);
        Norm { mag }
    }
}

impl Mode for Norm {
    fn handle(&mut self, event: &KeyEvent) -> Result<Action> {
        let mag = self.mag.parse::<u16>().ok();
        let def_mag = mag.unwrap_or(1);

        if clearable(&event.code) {
            self.mag.clear();
        }

        let action = match event.code {
            KeyCode::Char('q') => Action::Quit,
            KeyCode::Char('j') | KeyCode::Down => Action::RelDown(def_mag, ScrollUnit::Line),
            KeyCode::Char('k') | KeyCode::Up => Action::RelUp(def_mag, ScrollUnit::Line),
            KeyCode::Char('g') => Action::Goto(Position::Abs(def_mag.into())),

            KeyCode::Char('d') => Action::RelDown(def_mag, ScrollUnit::Half),
            KeyCode::Char('u') => Action::RelUp(def_mag, ScrollUnit::Half),
            KeyCode::Char('f') => Action::RelDown(def_mag, ScrollUnit::Page),
            KeyCode::Char('b') => Action::RelUp(def_mag, ScrollUnit::Page),

            KeyCode::Char('D') => Action::Delete,
            KeyCode::Char('U') => Action::Undo,
            KeyCode::Char('G') => {
                let pos = mag
                    .map(|i| Position::Abs(i.checked_sub(1).unwrap_or(1).into()))
                    .unwrap_or(Position::Last);

                Action::Goto(pos)
            }

            KeyCode::Char('n') => Action::Next,
            KeyCode::Char('N') => Action::Prev,

            KeyCode::Char('/') => Action::StartSearch,
            KeyCode::Enter => Action::Open,

            KeyCode::Char(ch) if ('0'..='9').contains(&ch) => {
                self.mag.push(ch);
                Action::Noop
            }

            _ => Action::Noop,
        };

        Ok(action)
    }

    fn status(&self) -> Option<String> {
        None
    }
}

fn clearable(code: &KeyCode) -> bool {
    if let KeyCode::Char(ch) = code {
        ('0'..='9').contains(ch)
    } else {
        false
    }
}