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