xref: /Held/src/utils/ui/mode/common.rs (revision fcc6ced0d18453415ce4b88b047a4e8e424fc693)
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 }
138