xref: /Held/src/utils/ui/mode/normal.rs (revision c2100e27aa48126d72fb7b1fd875b0c0f48cf395)
1 use lazy_static::lazy_static;
2 
3 use crate::utils::ui::event::KeyEventCallback;
4 use crate::utils::ui::event::WarpUiCallBackType;
5 use crate::utils::ui::uicore::UiCore;
6 use crate::utils::ui::uicore::CONTENT_WINSIZE;
7 use std::io;
8 use std::sync::{Mutex, MutexGuard};
9 
10 use super::common::CommonOp;
11 use super::mode::ModeType;
12 use super::state::StateMachine;
13 use crate::utils::ui::mode::state::StateCallback;
14 
15 #[derive(Debug)]
16 #[allow(dead_code)]
17 pub enum BufOpArg {
18     Around,    // 操作引号内乃至引号的内容
19     Inside,    // 操作引号内的内容
20     Line,      // 操作整行
21     Word,      // 操作单词
22     WordEnd,   // 操作单词的末尾
23     WordBegin, // 操作单词的开头
24     Block,     // 操作块
25 }
26 
27 #[derive(Debug)]
28 pub struct NormalState {
29     pub cmdchar: Option<char>,
30     pub count: Option<usize>,
31     pub count0: bool,
32     pub start_pos: Option<(u16, u16)>,
33     pub end_pos: Option<(u16, u16)>,
34     pub cmdbuf: Vec<u8>,
35     pub buf_op_arg: Option<BufOpArg>,
36 }
37 
38 impl CommonOp for NormalState {}
39 
40 lazy_static! {
41     static ref NORMALSTATE: Mutex<NormalState> = Mutex::new(NormalState {
42         cmdchar: None,       // 命令开头的字符,通常决定了一类功能,如dw,dd系列命令
43         count: None,         // 命令的重复次数,如3j,4k
44         count0: false,       // 是否将0作为命令的一部分,在normal模式下,0是一个独立的命令,也可能是一个数字的一部分
45         start_pos: None,     // 作用区域的起始位置
46         end_pos: None,       // 作用区域的结束位置
47         cmdbuf: Vec::new(),  // 用于存储输入的命令,可以与状态的显示通用?
48         buf_op_arg: None // 用于指定操作的区域,如daw,diw
49     });
50 }
51 
52 #[derive(Debug)]
53 pub(crate) struct Normal;
54 impl Normal {
new() -> Self55     pub fn new() -> Self {
56         Self {}
57     }
58 }
59 
60 impl KeyEventCallback for Normal {
backspace(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType>61     fn backspace(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> {
62         return Ok(WarpUiCallBackType::None);
63     }
esc(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType>64     fn esc(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> {
65         return Ok(WarpUiCallBackType::ChangMode(ModeType::Command));
66     }
67 
enter(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType>68     fn enter(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> {
69         return Ok(WarpUiCallBackType::None);
70     }
tab(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType>71     fn tab(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> {
72         return Ok(WarpUiCallBackType::None);
73     }
input_data( &self, ui: &mut MutexGuard<UiCore>, data: &[u8], ) -> io::Result<WarpUiCallBackType>74     fn input_data(
75         &self,
76         ui: &mut MutexGuard<UiCore>,
77         data: &[u8],
78     ) -> io::Result<WarpUiCallBackType> {
79         let mut normal_state = NORMALSTATE.lock().unwrap();
80         normal_state.cmdbuf.extend_from_slice(data);
81         match data {
82             b"h" => normal_state.on_h_clicked(),
83 
84             b"j" => normal_state.on_j_clicked(),
85 
86             b"k" => normal_state.on_k_clicked(),
87 
88             b"l" => normal_state.on_l_clicked(),
89 
90             b"i" => normal_state.on_i_clicked(),
91 
92             b"d" => normal_state.on_d_clicked(),
93 
94             [b'1'..=b'9'] => normal_state.on_nonzero_clicked(data),
95 
96             b"0" => normal_state.on_zero_clicked(),
97 
98             b"w" => normal_state.on_w_clicked(ui),
99 
100             b"g" => normal_state.on_g_clicked(),
101 
102             b"G" => normal_state.on_G_clicked(ui),
103 
104             b"b" => normal_state.on_b_clicked(ui),
105 
106             b":" => {
107                 if normal_state.cmdchar.is_none() {
108                     ui.cursor.store_pos();
109                     return Ok(WarpUiCallBackType::ChangMode(ModeType::LastLine));
110                 }
111             }
112 
113             b"$" => normal_state.on_dollar_clicked(),
114 
115             b"e" => normal_state.on_e_clicked(ui),
116 
117             b"f" => normal_state.on_f_clicked(),
118 
119             b"F" => normal_state.on_F_clicked(),
120 
121             b"x" => normal_state.on_x_clicked(),
122 
123             b"o" => normal_state.on_o_clicked(),
124 
125             b"O" => normal_state.on_O_clicked(),
126 
127             b"a" => normal_state.on_a_clicked(),
128 
129             b"A" => normal_state.on_A_clicked(),
130 
131             b"I" => normal_state.on_I_clicked(),
132 
133             b"H" => normal_state.on_H_clicked(),
134 
135             b"M" => normal_state.on_M_clicked(),
136 
137             _ => {}
138         }
139         return normal_state.handle(ui);
140     }
141 }
142 
143 impl KeyEventCallback for NormalState {
backspace(&self, ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType>144     fn backspace(&self, ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> {
145         ui.cursor.move_left(1)?;
146         return Ok(WarpUiCallBackType::None);
147     }
148 
esc(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType>149     fn esc(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> {
150         return Ok(WarpUiCallBackType::ChangMode(ModeType::Command));
151     }
152 
enter(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType>153     fn enter(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> {
154         return Ok(WarpUiCallBackType::None);
155     }
156 
tab(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType>157     fn tab(&self, _ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> {
158         return Ok(WarpUiCallBackType::None);
159     }
160 
input_data( &self, _ui: &mut MutexGuard<UiCore>, _data: &[u8], ) -> io::Result<WarpUiCallBackType>161     fn input_data(
162         &self,
163         _ui: &mut MutexGuard<UiCore>,
164         _data: &[u8],
165     ) -> io::Result<WarpUiCallBackType> {
166         return Ok(WarpUiCallBackType::None);
167     }
168 }
169 impl NormalState {
exec_0_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>170     pub fn exec_0_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
171         ui.cursor.move_to_columu(0)?;
172         return Ok(StateCallback::Reset);
173     }
174 
on_h_clicked(&mut self)175     pub fn on_h_clicked(&mut self) {
176         if self.cmdchar.is_none() {
177             self.cmdchar = Some('h');
178         }
179     }
180     /// 向左移动数列
exec_h_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>181     pub fn exec_h_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
182         let old_x = ui.cursor.x();
183         let exec_count = match self.count {
184             Some(count) => count.min(old_x as usize),
185             None => {
186                 if old_x == 0 {
187                     0
188                 } else {
189                     1
190                 }
191             } // 如果在第一列,不再向左移动,防止溢出
192         };
193         let new_x = old_x - exec_count as u16;
194         ui.cursor.move_to_columu(new_x)?;
195         return Ok(StateCallback::Reset);
196     }
197 
on_j_clicked(&mut self)198     pub fn on_j_clicked(&mut self) {
199         if self.cmdchar.is_none() {
200             self.cmdchar = Some('j');
201         }
202     }
203     /// 向下移动数行
exec_j_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>204     pub fn exec_j_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
205         let old_y = ui.cursor.y();
206         let old_abs_y = old_y + ui.buffer.offset() as u16;
207         // 限制最大移动行数
208         let exec_count = match self.count {
209             Some(count) => count.min(ui.buffer.line_count() - old_abs_y as usize - 1),
210             None => 1, // goto_line 会自动处理最大值
211         };
212         let old_offset = ui.buffer.offset();
213         let new_y = ui.buffer.goto_line(old_abs_y as usize + exec_count);
214         let new_linesize = ui.buffer.get_linesize(new_y);
215         let new_x = if new_linesize < ui.cursor.x() {
216             // 如果新行的长度小于原来的x坐标,将光标移动到新行的最后一个字符
217             new_linesize - 1
218         } else {
219             ui.cursor.x()
220         };
221         ui.cursor.move_to(new_x, new_y)?;
222         ui.cursor.highlight(Some(old_y))?;
223         // 如果移动后,buffer的offset发生了变化,需要重新渲染
224         if ui.buffer.offset() != old_offset {
225             ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?;
226         }
227         return Ok(StateCallback::Reset);
228     }
on_k_clicked(&mut self)229     pub fn on_k_clicked(&mut self) {
230         if self.cmdchar.is_none() {
231             self.cmdchar = Some('k');
232         }
233     }
234 
235     /// 向上移动数行
exec_k_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>236     pub fn exec_k_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
237         let old_y = ui.cursor.y();
238         let old_abs_y = old_y + ui.buffer.offset() as u16;
239         // 限制最大移动行数
240         let exec_count = match self.count {
241             Some(count) => count.min(old_y as usize + ui.buffer.offset()),
242             None => {
243                 if old_abs_y == 0 {
244                     0
245                 } else {
246                     1
247                 }
248             } // 如果在第一行,不再向上移动,防止溢出
249         };
250         let to_line = old_abs_y as usize - exec_count;
251         let old_offset = ui.buffer.offset();
252         let new_y = ui.buffer.goto_line(to_line);
253         let new_linesize = ui.buffer.get_linesize(new_y);
254         let new_x = if new_linesize < ui.cursor.x() {
255             // 如果新行的长度小于原来的x坐标,将光标移动到新行的最后一个字符
256             new_linesize - 1
257         } else {
258             ui.cursor.x()
259         };
260         ui.cursor.move_to(new_x, new_y)?;
261         ui.cursor.highlight(Some(old_y))?;
262         // 如果移动后,buffer的offset发生了变化,需要重新渲染
263         if old_offset != ui.buffer.offset() {
264             ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?;
265         }
266         return Ok(StateCallback::Reset);
267     }
268 
on_l_clicked(&mut self)269     pub fn on_l_clicked(&mut self) {
270         if self.cmdchar.is_none() {
271             self.cmdchar = Some('l');
272         }
273     }
274 
275     /// 向右移动数列
exec_l_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>276     pub fn exec_l_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
277         let old_x = ui.cursor.x();
278         let linesize = ui.buffer.get_linesize(ui.cursor.y()) as usize;
279         let max_count = linesize - old_x as usize - 1;
280         let exec_count = match self.count {
281             Some(count) => count.min(max_count),
282             None => {
283                 if old_x == linesize as u16 - 1 {
284                     0
285                 } else {
286                     1
287                 }
288             }
289         };
290         let new_x = old_x + exec_count as u16;
291         ui.cursor.move_to_columu(new_x)?;
292         return Ok(StateCallback::Reset);
293     }
294 
on_i_clicked(&mut self)295     pub fn on_i_clicked(&mut self) {
296         if self.cmdchar.is_none() {
297             self.cmdchar = Some('i');
298         }
299     }
exec_i_cmd(&mut self, _ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>300     pub fn exec_i_cmd(&mut self, _ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
301         return Ok(StateCallback::Exit(ModeType::Insert));
302     }
303 
304     #[allow(non_snake_case)]
on_I_clicked(&mut self)305     pub fn on_I_clicked(&mut self) {
306         if self.cmdchar.is_none() {
307             self.cmdchar = Some('I');
308         }
309     }
310 
311     // 切换Insert模式,从行首开始插入字符
312     #[allow(non_snake_case)]
exec_I_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>313     pub fn exec_I_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
314         ui.cursor.move_to_columu(0)?;
315         return Ok(StateCallback::Exit(ModeType::Insert));
316     }
317 
on_a_clicked(&mut self)318     pub fn on_a_clicked(&mut self) {
319         if self.cmdchar.is_none() {
320             self.cmdchar = Some('a');
321         }
322     }
323 
324     // 切换Insert模式,从当前位置的下一个字符开始插入
exec_a_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>325     pub fn exec_a_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
326         self.right(ui)?;
327         return Ok(StateCallback::Exit(ModeType::Insert));
328     }
329 
330     #[allow(non_snake_case)]
on_A_clicked(&mut self)331     pub fn on_A_clicked(&mut self) {
332         if self.cmdchar.is_none() {
333             self.cmdchar = Some('A');
334         }
335     }
336 
337     // 切换Insert模式,从行尾开始插入字符
338     #[allow(non_snake_case)]
exec_A_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>339     pub fn exec_A_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
340         let line_end = ui.buffer.get_linesize(ui.cursor.y()) - 1;
341         ui.cursor.move_to_columu(line_end)?;
342         return Ok(StateCallback::Exit(ModeType::Insert));
343     }
344 
on_o_clicked(&mut self)345     pub fn on_o_clicked(&mut self) {
346         if self.cmdchar.is_none() {
347             self.cmdchar = Some('o');
348         }
349     }
350 
351     // 切换Insert模式,在当前行的下方插入一个新行开始输入文本
exec_o_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>352     pub fn exec_o_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
353         let linesize = ui.buffer.get_linesize(ui.cursor.y());
354         ui.cursor.move_to_columu(linesize - 1)?;
355         ui.buffer.input_enter(ui.cursor.x(), ui.cursor.y());
356         ui.cursor.move_to_nextline(1)?;
357         return Ok(StateCallback::Exit(ModeType::Insert));
358     }
359 
360     #[allow(non_snake_case)]
on_O_clicked(&mut self)361     pub fn on_O_clicked(&mut self) {
362         if self.cmdchar.is_none() {
363             self.cmdchar = Some('O');
364         }
365     }
366 
367     // 切换Insert模式,在当前行的上方插入一个新行开始输入文本
368     #[allow(non_snake_case)]
exec_O_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>369     pub fn exec_O_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
370         ui.cursor.move_to_columu(0)?;
371         ui.buffer.input_enter(ui.cursor.x(), ui.cursor.y());
372         return Ok(StateCallback::Exit(ModeType::Insert));
373     }
374 
375     /// 处理输入的非零数字
on_nonzero_clicked(&mut self, data: &[u8])376     pub fn on_nonzero_clicked(&mut self, data: &[u8]) {
377         let count = self.count;
378         if count.is_none() {
379             // 如果count为空,将第一个输入的数字作为count
380             let count = data[0] - b'0';
381             self.count = Some(count as usize);
382         } else {
383             // 如果count不为空,将输入的数字添加到count的末尾
384             let mut count = count.unwrap();
385             count = count * 10 + (data[0] - b'0') as usize;
386             self.count = Some(count);
387         }
388         self.count0 = true; // 将后续输入的0作为执行次数的一部分
389     }
390 
391     /// 处理输入的0
on_zero_clicked(&mut self)392     pub fn on_zero_clicked(&mut self) {
393         // 如果0是命令的一部分,不再处理
394         if !self.count0 && self.cmdchar.is_none() {
395             self.cmdchar = Some('0');
396             self.count0 = true;
397         }
398         let count = self.count;
399         // 如果输入的是0,且count不为空,将count扩大10倍
400         if count.is_some() {
401             let mut count = count.unwrap();
402             count = count * 10;
403             self.count = Some(count);
404         }
405     }
406 
407     /// 处理输入的d
on_d_clicked(&mut self)408     pub fn on_d_clicked(&mut self) {
409         match self.cmdchar {
410             None => {
411                 // 处理d
412                 self.cmdchar = Some('d');
413             }
414             Some('d') => {
415                 // 处理dd
416                 self.buf_op_arg = Some(BufOpArg::Line);
417             }
418             _ => {
419                 self.reset();
420             }
421         }
422     }
423 
exec_d_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>424     pub fn exec_d_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
425         let count = match self.count {
426             Some(count) => count as u16,
427             None => 1,
428         };
429         match self.buf_op_arg {
430             Some(BufOpArg::Line) => {
431                 // 删除行
432                 self.remove_n_line(ui, count)?;
433                 return Ok(StateCallback::Reset);
434             }
435             Some(BufOpArg::Word) => {
436                 // 删除单词
437                 for _ in 0..count {
438                     self.remove_word(ui)?;
439                 }
440                 return Ok(StateCallback::Reset);
441             }
442             _ => {
443                 return Ok(StateCallback::None);
444             }
445         }
446     }
447 
on_w_clicked(&mut self, ui: &mut MutexGuard<UiCore>)448     pub fn on_w_clicked(&mut self, ui: &mut MutexGuard<UiCore>) {
449         if self.cmdchar.is_none() {
450             // 按单词移动
451             self.cmdchar = Some('w');
452             let count = match self.count {
453                 Some(count) => count,
454                 None => 1,
455             };
456             let mut pos = (ui.cursor.x(), ui.cursor.y() + ui.buffer.offset() as u16);
457             for _ in 0..count {
458                 pos = self.locate_next_word(ui, pos);
459             }
460             self.end_pos = Some(pos);
461         } else {
462             // 按单词操作,具体由self.cmdchar决定
463             self.buf_op_arg = Some(BufOpArg::Word);
464         }
465     }
466 
exec_w_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>467     pub fn exec_w_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
468         self.end_pos.map(|pos| {
469             self.move_to_line(ui, pos.1).unwrap();
470             ui.cursor.move_to_columu(pos.0).unwrap();
471         });
472         return Ok(StateCallback::Reset);
473     }
474 
on_g_clicked(&mut self)475     fn on_g_clicked(&mut self) {
476         if self.cmdchar.is_none() {
477             self.cmdchar = Some('g');
478         } else {
479             self.end_pos = Some((0, 0));
480         }
481     }
482 
exec_g_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>483     fn exec_g_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
484         let rs = self
485             .end_pos
486             .map(|pos| self.move_to_line(ui, pos.1).unwrap());
487         if let None = rs {
488             return Ok(StateCallback::None);
489         }
490         return Ok(StateCallback::Reset);
491     }
492 
493     #[allow(non_snake_case)]
on_G_clicked(&mut self, _ui: &mut MutexGuard<UiCore>)494     fn on_G_clicked(&mut self, _ui: &mut MutexGuard<UiCore>) {
495         if self.cmdchar.is_none() {
496             self.cmdchar = Some('G');
497         }
498     }
499 
500     #[allow(non_snake_case)]
exec_G_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>501     fn exec_G_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
502         let lineidx = match self.count {
503             Some(count) => count - 1,
504             None => ui.buffer.line_count() - 1,
505         };
506         self.move_to_line(ui, lineidx as u16)?;
507         return Ok(StateCallback::Reset);
508     }
509 
on_b_clicked(&mut self, ui: &mut MutexGuard<UiCore>)510     fn on_b_clicked(&mut self, ui: &mut MutexGuard<UiCore>) {
511         if self.cmdchar.is_none() {
512             self.cmdchar = Some('b');
513         } else {
514             self.buf_op_arg = Some(BufOpArg::WordBegin);
515         }
516         let count = match self.count {
517             Some(count) => count,
518             None => 1,
519         };
520         let mut pos = (ui.cursor.x(), ui.cursor.y() + ui.buffer.offset() as u16);
521         self.start_pos = Some(pos);
522         for _ in 0..count {
523             pos = self.locate_prevw_begin(ui, pos.0, pos.1);
524         }
525         self.end_pos = Some(pos);
526     }
527 
exec_b_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>528     fn exec_b_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
529         let end_pos = self.end_pos.unwrap();
530         self.move_to_line(ui, end_pos.1)?;
531         ui.cursor.move_to_columu(end_pos.0)?;
532         return Ok(StateCallback::Reset);
533     }
534 
on_dollar_clicked(&mut self)535     fn on_dollar_clicked(&mut self) {
536         if self.cmdchar.is_none() {
537             self.cmdchar = Some('$');
538         }
539     }
540 
exec_dollar_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>541     fn exec_dollar_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
542         let line_end = ui.buffer.get_linesize(ui.cursor.y()) as u16 - 1;
543         ui.cursor.move_to_columu(line_end)?;
544         return Ok(StateCallback::Reset);
545     }
546 
on_e_clicked(&mut self, ui: &mut MutexGuard<UiCore>)547     fn on_e_clicked(&mut self, ui: &mut MutexGuard<UiCore>) {
548         if self.cmdchar.is_none() {
549             self.cmdchar = Some('e');
550         } else {
551             self.buf_op_arg = Some(BufOpArg::WordEnd);
552         }
553         let count = match self.count {
554             Some(count) => count,
555             None => 1,
556         };
557         let mut pos = (ui.cursor.x(), ui.cursor.y() + ui.buffer.offset() as u16);
558         for _ in 0..count {
559             pos = self.locate_nextw_ending(ui, pos.0, pos.1);
560         }
561         self.end_pos = Some(pos);
562     }
563 
exec_e_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>564     fn exec_e_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
565         let end_pos = self.end_pos;
566         if end_pos.is_none() {
567             return Ok(StateCallback::None);
568         }
569         let end_pos = end_pos.unwrap();
570         self.move_to_line(ui, end_pos.1)?;
571         ui.cursor.move_to_columu(end_pos.0)?;
572         return Ok(StateCallback::Reset);
573     }
574 
on_f_clicked(&mut self)575     fn on_f_clicked(&mut self) {
576         if self.cmdchar.is_none() {
577             self.cmdchar = Some('f');
578         }
579     }
580 
exec_f_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>581     fn exec_f_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
582         if self.cmdbuf.len() < 2 {
583             return Ok(StateCallback::None);
584         }
585         let to_find = self.cmdbuf.last().unwrap().clone() as char;
586         let old_x = ui.cursor.x();
587         let old_y = ui.cursor.y();
588         let line =
589             String::from_utf8_lossy(&ui.buffer.get_line(old_y)[old_x as usize..]).to_string();
590         let pos = line.find(to_find);
591         if pos.is_none() {
592             return Ok(StateCallback::None);
593         }
594         ui.cursor
595             .move_to_columu((old_x + pos.unwrap() as u16) as u16)?;
596         return Ok(StateCallback::Reset);
597     }
598 
599     #[allow(non_snake_case)]
on_F_clicked(&mut self)600     fn on_F_clicked(&mut self) {
601         if self.cmdchar.is_none() {
602             self.cmdchar = Some('F');
603         }
604     }
605 
606     #[allow(non_snake_case)]
exec_F_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>607     fn exec_F_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
608         if self.cmdbuf.len() < 2 {
609             return Ok(StateCallback::None);
610         }
611         let to_find = self.cmdbuf.last().unwrap().clone() as char;
612         let old_x = ui.cursor.x();
613         let old_y = ui.cursor.y();
614         let line =
615             String::from_utf8_lossy(&ui.buffer.get_line(old_y)[..old_x as usize]).to_string();
616         let pos = line.rfind(to_find);
617         if pos.is_none() {
618             return Ok(StateCallback::None);
619         }
620         ui.cursor.move_to_columu(pos.unwrap() as u16)?;
621         return Ok(StateCallback::Reset);
622     }
623 
on_x_clicked(&mut self)624     fn on_x_clicked(&mut self) {
625         if self.cmdchar.is_none() {
626             self.cmdchar = Some('x');
627         }
628     }
629 
exec_x_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>630     fn exec_x_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
631         let y = ui.cursor.y();
632         let x = ui.cursor.x();
633         if x < ui.buffer.get_linesize(y) - 1 {
634             ui.buffer.remove_char(x, y);
635             ui.render_content(y, 1)?;
636         }
637         return Ok(StateCallback::Reset);
638     }
639 
640     #[allow(non_snake_case)]
on_H_clicked(&mut self)641     fn on_H_clicked(&mut self) {
642         if self.cmdchar.is_none() {
643             self.cmdchar = Some('H');
644         }
645     }
646 
647     #[allow(non_snake_case)]
exec_H_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>648     fn exec_H_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
649         self.move_to_nlines_of_screen(ui, 0)?;
650         return Ok(StateCallback::Reset);
651     }
652     #[allow(non_snake_case)]
on_M_clicked(&mut self)653     fn on_M_clicked(&mut self) {
654         if self.cmdchar.is_none() {
655             self.cmdchar = Some('M');
656         }
657     }
658 
659     #[allow(non_snake_case)]
exec_M_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback>660     fn exec_M_cmd(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<StateCallback> {
661         let win_size = CONTENT_WINSIZE.read().unwrap().rows as usize;
662         self.move_to_nlines_of_screen(ui, win_size / 2)?;
663         return Ok(StateCallback::Reset);
664     }
665 }
666 
667 impl StateMachine for NormalState {
reset(&mut self)668     fn reset(&mut self) {
669         self.cmdchar = None;
670         self.count = None;
671         self.count0 = false;
672         self.start_pos = None;
673         self.end_pos = None;
674         self.cmdbuf.clear();
675         self.buf_op_arg = None;
676     }
handle(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType>677     fn handle(&mut self, ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> {
678         if self.cmdchar.is_none() {
679             return Ok(WarpUiCallBackType::None);
680         }
681         let state_callback = match self.cmdchar.unwrap() {
682             'h' => self.exec_h_cmd(ui),
683             'j' => self.exec_j_cmd(ui),
684             'k' => self.exec_k_cmd(ui),
685             'l' => self.exec_l_cmd(ui),
686             'i' => self.exec_i_cmd(ui),
687             '0' => self.exec_0_cmd(ui),
688             'd' => self.exec_d_cmd(ui),
689             'w' => self.exec_w_cmd(ui),
690             'g' => self.exec_g_cmd(ui),
691             'G' => self.exec_G_cmd(ui),
692             'b' => self.exec_b_cmd(ui),
693             '$' => self.exec_dollar_cmd(ui),
694             'e' => self.exec_e_cmd(ui),
695             'f' => self.exec_f_cmd(ui),
696             'F' => self.exec_F_cmd(ui),
697             'x' => self.exec_x_cmd(ui),
698             'o' => self.exec_o_cmd(ui),
699             'O' => self.exec_O_cmd(ui),
700             'a' => self.exec_a_cmd(ui),
701             'A' => self.exec_A_cmd(ui),
702             'I' => self.exec_I_cmd(ui),
703             'H' => self.exec_H_cmd(ui),
704             'M' => self.exec_M_cmd(ui),
705             _ => Ok(StateCallback::None),
706         };
707         return match state_callback {
708             Ok(StateCallback::None) => Ok(WarpUiCallBackType::None),
709             Ok(StateCallback::Reset) => {
710                 self.reset();
711                 Ok(WarpUiCallBackType::None)
712             }
713             Ok(StateCallback::Exit(mode)) => self.exit(WarpUiCallBackType::ChangMode(mode)),
714             Err(e) => Err(e),
715         };
716     }
717 
exit(&mut self, callback: WarpUiCallBackType) -> io::Result<WarpUiCallBackType>718     fn exit(&mut self, callback: WarpUiCallBackType) -> io::Result<WarpUiCallBackType> {
719         self.reset();
720         Ok(callback)
721     }
722 }
723