Skip to content

Commit fcc6ced

Browse files
authored
Feat statemachine (#16)
1 parent 2d55501 commit fcc6ced

File tree

6 files changed

+878
-14
lines changed

6 files changed

+878
-14
lines changed

src/utils/buffer.rs

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ pub struct EditBuffer {
7979
locked_lines: RwLock<HashMap<usize, usize>>,
8080
}
8181

82-
#[allow(unused)]
8382
impl EditBuffer {
8483
pub fn new(buf: Vec<u8>) -> Self {
8584
let mut lines = buf
@@ -157,6 +156,18 @@ impl EditBuffer {
157156
line.data.len() as u16
158157
}
159158

159+
pub fn get_linesize_abs(&self, line: u16) -> u16 {
160+
let buf = self.buf.read().unwrap();
161+
let line = buf.get(line as usize);
162+
if line.is_none() {
163+
return 0;
164+
}
165+
166+
let line = line.unwrap();
167+
168+
line.data.len() as u16
169+
}
170+
160171
/// 外部接口,本结构体内部方法不应该使用,因为涉及offset计算
161172
pub fn remove_char(&self, x: u16, y: u16) {
162173
let mut buf = self.buf.write().unwrap();
@@ -379,7 +390,11 @@ impl EditBuffer {
379390

380391
pub fn delete_line(&self, y: usize) {
381392
let mut buffer = self.buf.write().unwrap();
382-
let line = buffer.get(y).unwrap();
393+
let line = buffer.get(y);
394+
if line.is_none() {
395+
return;
396+
}
397+
let line = line.unwrap();
383398
if line.data.is_empty() {
384399
return;
385400
}
@@ -389,17 +404,20 @@ impl EditBuffer {
389404
}
390405
}
391406

407+
/// 删除 y 行 0..x 的字符
392408
pub fn delete_until_line_beg(&self, x: usize, y: usize) -> Option<usize> {
393409
let mut buffer = self.buf.write().unwrap();
394410
let line = buffer.get_mut(y).unwrap();
395411

396-
if line.data.len() < 2 {
412+
let len = line.data.len();
413+
if len < 2 {
397414
return None;
398415
}
399-
line.data.drain(0..x);
416+
line.data.drain(0..x.min(len - 1));
400417
return Some(x - 1);
401418
}
402419

420+
/// 删除 y 行 x..end 的字符
403421
pub fn delete_until_endl(&self, x: usize, y: usize) -> Option<usize> {
404422
let mut buffer = self.buf.write().unwrap();
405423
let line = buffer.get_mut(y).unwrap();
@@ -418,13 +436,17 @@ impl EditBuffer {
418436
let mut right = left;
419437
let linesize = self.get_linesize(y) as usize;
420438
let buf = self.buf.read().unwrap();
421-
let line = buf
422-
.get(self.offset.load(Ordering::SeqCst) + y as usize)
423-
.unwrap();
439+
let line = match buf.get(self.offset.load(Ordering::SeqCst) + y as usize) {
440+
Some(line) => line,
441+
None => return x as usize,
442+
};
424443

425444
while left <= right && right < linesize {
426445
let lchar = line[left] as char;
427446
let rchar = line[right] as char;
447+
if rchar.is_ascii_punctuation() && right != x.into() {
448+
break;
449+
}
428450
if !(lchar == ' ' || lchar == '\t') {
429451
left += 1;
430452
right += 1;
@@ -446,13 +468,17 @@ impl EditBuffer {
446468
let mut right = left;
447469
let linesize = self.get_linesize(y) as usize;
448470
let buf = self.buf.read().unwrap();
449-
let line = buf
450-
.get(self.offset.load(Ordering::SeqCst) + y as usize)
451-
.unwrap();
471+
let line = match buf.get(self.offset.load(Ordering::SeqCst) + y as usize) {
472+
Some(line) => line,
473+
None => return x as usize,
474+
};
452475

453476
while left <= right && right < linesize {
454477
let lchar = line[left] as char;
455478
let rchar = line[right] as char;
479+
if rchar.is_ascii_punctuation() && right != x.into() {
480+
break;
481+
}
456482
if lchar == ' ' || lchar == '\t' {
457483
left += 1;
458484
right += 1;
@@ -477,14 +503,17 @@ impl EditBuffer {
477503
let mut left = x as i32;
478504
let mut right = left;
479505
let buf = self.buf.read().unwrap();
480-
let line = buf
481-
.get(self.offset.load(Ordering::SeqCst) + y as usize)
482-
.unwrap();
483-
506+
let line = match buf.get(self.offset.load(Ordering::SeqCst) + y as usize) {
507+
Some(line) => line,
508+
None => return Some(x as usize),
509+
};
484510
while left <= right && left >= 0 {
485511
let lchar = line[left as usize] as char;
486512
let rchar = line[right as usize] as char;
487513

514+
if lchar.is_ascii_punctuation() && left != x.into() {
515+
return Some(left as usize);
516+
}
488517
if rchar == ' ' || rchar == '\t' {
489518
left -= 1;
490519
right -= 1;
@@ -503,6 +532,36 @@ impl EditBuffer {
503532
}
504533
return None;
505534
}
535+
pub fn search_prevw_begin_abs(&self, x: u16, abs_y: u16) -> usize {
536+
let mut left = x as i32;
537+
let mut right = left;
538+
let buf = self.buf.read().unwrap();
539+
let line = buf.get(abs_y as usize).unwrap();
540+
while left <= right && left >= 0 {
541+
let lchar = line[left as usize] as char;
542+
let rchar = line[right as usize] as char;
543+
544+
if lchar.is_ascii_punctuation() && left != x.into() {
545+
return left as usize;
546+
}
547+
if rchar == ' ' || rchar == '\t' {
548+
left -= 1;
549+
right -= 1;
550+
continue;
551+
}
552+
553+
if lchar == ' ' || lchar == '\t' {
554+
if left + 1 == x.into() {
555+
right = left;
556+
continue;
557+
}
558+
return left as usize + 1;
559+
}
560+
561+
left -= 1;
562+
}
563+
return 0;
564+
}
506565
}
507566

508567
bitflags! {

src/utils/ui/mode/common.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
use std::{io, sync::MutexGuard};
2+
3+
use crate::utils::{
4+
terminal::TermManager,
5+
ui::{
6+
event::{KeyEventCallback, WarpUiCallBackType},
7+
uicore::{UiCore, CONTENT_WINSIZE},
8+
},
9+
};
10+
11+
pub trait CommonOp: KeyEventCallback {
12+
fn remove_line(&self, ui: &mut MutexGuard<UiCore>) -> io::Result<()> {
13+
TermManager::clear_current_line()?;
14+
TermManager::clear_under_cursor()?;
15+
let y = ui.cursor.y() as usize;
16+
let old_line_count = ui.buffer.line_count();
17+
let old_offset = ui.buffer.offset();
18+
19+
let count = old_line_count - y as usize;
20+
ui.buffer.delete_line(y + ui.buffer.offset() as usize);
21+
ui.render_content(y as u16, count.max(1))?;
22+
23+
if y + old_offset == old_line_count - 1 {
24+
self.up(ui)?;
25+
}
26+
27+
if old_line_count == 1 {
28+
ui.cursor.move_to_columu(0)?;
29+
ui.buffer.insert_char('\n' as u8, 0, 0);
30+
ui.render_content(0, 1)?;
31+
}
32+
33+
Ok(())
34+
}
35+
36+
fn remove_n_line(&self, ui: &mut MutexGuard<UiCore>, n: u16) -> io::Result<()> {
37+
let linecount = ui.buffer.line_count() as u16;
38+
let y = ui.cursor.y();
39+
40+
// 实际能删除的行数
41+
let to_delete = n.min(linecount - y);
42+
for _ in 0..to_delete {
43+
self.remove_line(ui)?;
44+
}
45+
Ok(())
46+
}
47+
fn remove_word(&self, ui: &mut MutexGuard<UiCore>) -> io::Result<()> {
48+
let x = ui.cursor.x();
49+
let y = ui.cursor.y();
50+
let next_word_pos = ui.buffer.search_nextw_begin(x, y);
51+
let linesize = ui.buffer.get_linesize(y);
52+
53+
// 如果下一个单词在当前行,则删除当前单词
54+
if next_word_pos < linesize.into() {
55+
ui.buffer.remove_str(x, y, next_word_pos - x as usize);
56+
} else {
57+
// 如果下一个单词在下一行,则删除当前行剩余部分
58+
self.left(ui)?;
59+
ui.buffer.delete_line(y.into());
60+
self.down(ui)?;
61+
}
62+
ui.render_content(y, 1)?;
63+
return Ok(());
64+
}
65+
fn jump_to_next_word(&self, ui: &mut MutexGuard<UiCore>) -> io::Result<WarpUiCallBackType> {
66+
let x = ui.cursor.x();
67+
let y = ui.cursor.y();
68+
let pos = ui.buffer.search_nextw_begin(x, y);
69+
let linesize = ui.buffer.get_linesize(y);
70+
let abs_y = y + ui.buffer.offset() as u16;
71+
72+
if pos < linesize as usize {
73+
// 如果下一个单词在当前行,则移动光标到该单词的起始位置
74+
ui.cursor.move_to_columu(pos as u16)?;
75+
} else if y as usize + ui.buffer.offset() < ui.buffer.line_count() - 1 {
76+
// 如果当前行不是最后一行,则移动到下一行的单词起始位置
77+
let next_word_pos = ui.buffer.search_nextw_begin(0, y + 1) as u16;
78+
let next_linesize = ui.buffer.get_linesize_abs(abs_y + 1);
79+
self.down(ui)?;
80+
ui.cursor
81+
.move_to_columu(next_word_pos.min(next_linesize - 1))?;
82+
ui.cursor.highlight(Some(y))?;
83+
} else {
84+
// 如果当前行是最后一行,则移动到当前行的末尾
85+
ui.cursor.move_to_columu(linesize as u16 - 1)?;
86+
}
87+
return Ok(WarpUiCallBackType::None);
88+
}
89+
fn move_to_line(&self, ui: &mut MutexGuard<UiCore>, line: u16) -> io::Result<()> {
90+
let x = ui.cursor.x();
91+
let y = ui.cursor.y();
92+
let new_y = ui.buffer.goto_line(line as usize);
93+
let new_x = x.min(ui.buffer.get_linesize(new_y)) as u16;
94+
ui.cursor.move_to(new_x, new_y)?;
95+
ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?;
96+
ui.cursor.highlight(Some(y))?;
97+
return Ok(());
98+
}
99+
100+
fn locate_prevw_begin(&self, ui: &mut MutexGuard<UiCore>, x: u16, abs_y: u16) -> (u16, u16) {
101+
// 如果光标已在行首,则尝试移动到上一行的单词首字母
102+
if x == 0 {
103+
if abs_y == 0 {
104+
return (0, 0);
105+
}
106+
let last_y = abs_y - 1;
107+
let end_of_prev_line = ui.buffer.get_linesize_abs(last_y) - 1;
108+
let prev_word_pos = ui.buffer.search_prevw_begin_abs(end_of_prev_line, last_y);
109+
return (prev_word_pos as u16, last_y);
110+
}
111+
112+
let prev_word_pos = ui.buffer.search_prevw_begin_abs(x, abs_y);
113+
114+
return (prev_word_pos as u16, abs_y);
115+
}
116+
fn locate_nextw_ending(&self, ui: &mut MutexGuard<UiCore>, x: u16, y: u16) -> (u16, u16) {
117+
let linesize = ui.buffer.get_linesize(y) as usize;
118+
119+
// y的绝对位置
120+
let abs_y = ui.buffer.offset() as u16 + y;
121+
// 如果光标已经在当前行的末尾或最后一个字符(x + 2),则尝试移动到下一行的末尾或单词末尾
122+
if x as usize + 2 >= linesize {
123+
if abs_y < ui.buffer.line_count() as u16 - 1 {
124+
let next_end_pos = ui.buffer.search_nextw_end(0, y + 1) as u16;
125+
return (next_end_pos, abs_y + 1);
126+
} else {
127+
// 如果已经是最后一行,则保持光标在当前行的末尾
128+
let x = if linesize > 0 { linesize - 1 } else { 0 };
129+
return (x as u16, abs_y);
130+
}
131+
}
132+
133+
let next_end_pos = ui.buffer.search_nextw_end(x, y) as u16;
134+
// 如果下一个单词的末尾在当前行,则移动光标到该单词的末尾
135+
return (next_end_pos.min(linesize as u16 - 1), abs_y);
136+
}
137+
}

src/utils/ui/mode/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
pub mod common;
12
pub mod mode;
3+
pub mod normal;

src/utils/ui/mode/mode.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ use crate::utils::ui::{
1818

1919
use crate::utils::ui::event::WarpUiCallBackType;
2020

21+
use super::normal::Normal;
22+
2123
pub trait InputMode: KeyEventCallback + Debug {
2224
fn mode_type(&self) -> ModeType;
2325

@@ -105,6 +107,7 @@ pub enum ModeType {
105107
Command,
106108
LastLine,
107109
Insert,
110+
Normal,
108111
}
109112

110113
impl InputMode for Command {
@@ -122,6 +125,11 @@ impl InputMode for Insert {
122125
ModeType::Insert
123126
}
124127
}
128+
impl InputMode for Normal {
129+
fn mode_type(&self) -> ModeType {
130+
ModeType::Normal
131+
}
132+
}
125133

126134
#[derive(Debug)]
127135
pub struct Command;
@@ -557,6 +565,10 @@ impl KeyEventCallback for Command {
557565
return Ok(WarpUiCallBackType::None);
558566
}
559567

568+
b"n" => {
569+
return Ok(WarpUiCallBackType::ChangMode(ModeType::Normal));
570+
}
571+
560572
b"H" => {
561573
self.move_to_nlines_of_screen(ui, 0)?;
562574
return Ok(WarpUiCallBackType::None);

0 commit comments

Comments
 (0)