1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
use std::any::Any;
use std::fmt::Debug;
use std::sync::{
    atomic::{AtomicBool, AtomicI8, Ordering},
    Arc,
};

use anyhow::Result;
use downcast_rs::Downcast;
use panorama_tui::crossterm::event::{self, Event, KeyCode, KeyEvent};

use super::colon_prompt::ColonPrompt;
use super::TermType;

pub trait HandlesInput: Any + Debug + Downcast {
    fn handle_key(&mut self, term: TermType, evt: KeyEvent) -> Result<InputResult> {
        Ok(InputResult::Ok)
    }
}

downcast_rs::impl_downcast!(HandlesInput);

pub enum InputResult {
    Ok,

    /// Push a new state
    Push(Box<dyn HandlesInput>),

    /// Pops a state from the stack
    Pop,
}

#[derive(Debug)]
pub struct BaseInputHandler(pub Arc<AtomicBool>, pub Arc<AtomicI8>);

impl HandlesInput for BaseInputHandler {
    fn handle_key(&mut self, term: TermType, evt: KeyEvent) -> Result<InputResult> {
        let KeyEvent { code, .. } = evt;
        match code {
            KeyCode::Char('q') => self.0.store(true, Ordering::Relaxed),
            KeyCode::Char('j') => self.1.store(1, Ordering::Relaxed),
            KeyCode::Char('k') => self.1.store(-1, Ordering::Relaxed),
            KeyCode::Char(':') => {
                let colon_prompt = Box::new(ColonPrompt::init(term)?);
                return Ok(InputResult::Push(colon_prompt));
            }
            _ => {}
        }

        Ok(InputResult::Ok)
    }
}