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}