cyndikator 0.1.0

A cli rss reader
use crossterm::{
    event::{Event, KeyCode, KeyEvent},
    Result,
};

use super::Action;

pub struct Inter {
    pub height: u16,
    pub offset: u16,
    pub base: u32,
    pub mag: String,
}

impl Inter {
    pub fn new(height: u16, base: u32) -> Inter {
        let offset = 0;
        let mag = String::new();

        Inter {
            offset,
            height,
            base,
            mag,
        }
    }

    pub fn interact(&mut self, event: &Event) -> Result<Action> {
        match event {
            Event::Key(ke) => return self.inter_key(ke),

            Event::Resize(_, height) => self.height = *height,

            _ => (),
        };

        Ok(Action::Noop)
    }

    fn inter_key(&mut self, event: &KeyEvent) -> Result<Action> {
        let mag = self.mag.parse::<u16>().ok();

        match event.code {
            KeyCode::Char('q') => return Ok(Action::Quit),
            KeyCode::Char('j') | KeyCode::Down => {
                self.move_down(mag.unwrap_or(1));
                self.mag.clear();
            }

            KeyCode::Char('k') | KeyCode::Up => {
                self.move_up(mag.unwrap_or(1));
                self.mag.clear();
            }

            KeyCode::Char('g') => {
                self.goto(mag.unwrap_or(1) as u32);
                self.mag.clear();
            }

            KeyCode::Char('G') => {
                self.offset = mag
                    .map(|i| i.checked_sub(1).unwrap_or(1))
                    .unwrap_or(u16::MAX);
                self.mag.clear();
            }

            KeyCode::Char('d') => {
                self.move_down(mag.unwrap_or(1) * self.height / 2);
                self.mag.clear();
            }

            KeyCode::Char('u') => {
                self.move_up(mag.unwrap_or(1) * self.height / 2);
                self.mag.clear();
            }

            KeyCode::Char('f') => {
                self.move_down(mag.unwrap_or(1) * self.height);
                self.mag.clear();
            }

            KeyCode::Char('b') => {
                self.move_up(mag.unwrap_or(1) * self.height);
                self.mag.clear();
            }

            KeyCode::Char('D') => {
                self.mag.clear();
                return Ok(Action::Delete);
            }

            KeyCode::Char('U') => {
                self.mag.clear();
                return Ok(Action::Undo);
            }

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

            KeyCode::Enter => {
                self.mag.clear();
                return Ok(Action::Open);
            }

            _ => (),
        };

        Ok(Action::Noop)
    }

    fn move_down(&mut self, amount: u16) {
        self.offset += amount;

        if self.offset >= self.height {
            self.base += (self.offset - self.height + 1) as u32;
            self.offset = self.height - 1;
        }
    }

    fn move_up(&mut self, amount: u16) {
        let diff = if amount > self.offset {
            amount - self.offset
        } else {
            0
        };

        self.offset = self.offset.checked_sub(amount).unwrap_or(0);
        self.base = self.base.checked_sub(diff as u32).unwrap_or(0);
    }

    fn goto(&mut self, line: u32) {
        let adjusted = line.checked_sub(1).unwrap_or(0);

        if adjusted < self.base {
            self.base = adjusted;
            self.offset = 0;
        } else {
            self.offset = (adjusted - self.base) as u16;
        }
    }
}