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