Skip to main content

vim_navigator/
lib.rs

1use crossterm::event::{KeyCode, KeyEvent};
2
3#[derive(Debug, Clone, PartialEq)]
4pub enum InputMode {
5    Normal,
6    Command,
7    Insert,
8}
9
10#[derive(Debug, Clone, PartialEq)]
11pub enum NavAction {
12    None,
13    ModeChange(InputMode),
14    Command(String),
15    MoveUp,
16    MoveDown,
17    MoveTop,
18    MoveBottom,
19    Quit,
20}
21
22pub struct VimNavigator {
23    pub mode: InputMode,
24    pub command_buffer: String,
25}
26
27impl VimNavigator {
28    pub fn new() -> Self {
29        Self {
30            mode: InputMode::Normal,
31            command_buffer: String::new(),
32        }
33    }
34
35    pub fn handle_key(&mut self, key: KeyEvent) -> NavAction {
36        match self.mode {
37            InputMode::Normal => self.handle_normal_mode(key),
38            InputMode::Command => self.handle_command_mode(key),
39            InputMode::Insert => NavAction::None,
40        }
41    }
42
43    fn handle_normal_mode(&mut self, key: KeyEvent) -> NavAction {
44        match key.code {
45            KeyCode::Char('q') => NavAction::Quit,
46            KeyCode::Char(':') => {
47                self.mode = InputMode::Command;
48                self.command_buffer.clear();
49                NavAction::ModeChange(InputMode::Command)
50            }
51            KeyCode::Char('i') => {
52                self.mode = InputMode::Insert;
53                NavAction::ModeChange(InputMode::Insert)
54            }
55            KeyCode::Char('j') | KeyCode::Down => NavAction::MoveDown,
56            KeyCode::Char('k') | KeyCode::Up => NavAction::MoveUp,
57            KeyCode::Char('g') => NavAction::MoveTop,
58            KeyCode::Char('G') => NavAction::MoveBottom,
59            KeyCode::Esc => {
60                self.mode = InputMode::Normal;
61                NavAction::ModeChange(InputMode::Normal)
62            }
63            _ => NavAction::None,
64        }
65    }
66
67    fn handle_command_mode(&mut self, key: KeyEvent) -> NavAction {
68        match key.code {
69            KeyCode::Esc => {
70                self.mode = InputMode::Normal;
71                self.command_buffer.clear();
72                NavAction::ModeChange(InputMode::Normal)
73            }
74            KeyCode::Enter => {
75                let cmd = self.command_buffer.clone();
76                self.mode = InputMode::Normal;
77                self.command_buffer.clear();
78                NavAction::Command(cmd)
79            }
80            KeyCode::Backspace => {
81                self.command_buffer.pop();
82                NavAction::None
83            }
84            KeyCode::Char(c) => {
85                self.command_buffer.push(c);
86                NavAction::None
87            }
88            _ => NavAction::None,
89        }
90    }
91
92    pub fn exit_insert_mode(&mut self) {
93        self.mode = InputMode::Normal;
94    }
95}
96
97impl Default for VimNavigator {
98    fn default() -> Self {
99        Self::new()
100    }
101}
102
103pub struct ListNavigator {
104    pub selected_index: usize,
105}
106
107impl ListNavigator {
108    pub fn new() -> Self {
109        Self { selected_index: 0 }
110    }
111
112    pub fn move_up(&mut self) {
113        self.selected_index = self.selected_index.saturating_sub(1);
114    }
115
116    pub fn move_down(&mut self, list_len: usize) {
117        if list_len > 0 {
118            self.selected_index = (self.selected_index + 1).min(list_len - 1);
119        }
120    }
121
122    pub fn move_top(&mut self) {
123        self.selected_index = 0;
124    }
125
126    pub fn move_bottom(&mut self, list_len: usize) {
127        if list_len > 0 {
128            self.selected_index = list_len - 1;
129        }
130    }
131
132    pub fn reset(&mut self) {
133        self.selected_index = 0;
134    }
135
136    pub fn selected(&self) -> usize {
137        self.selected_index
138    }
139}
140
141impl Default for ListNavigator {
142    fn default() -> Self {
143        Self::new()
144    }
145}