xref: /Held/src/utils/cursor.rs (revision c775ed96190e893de2e6dd160a742b2329b8c15c)
1 use std::{
2     fmt::Display,
3     io::{self, stdout, Write},
4     sync::Arc,
5 };
6 
7 use crossterm::{
8     cursor::{
9         Hide, MoveDown, MoveLeft, MoveRight, MoveTo, MoveToColumn, MoveToNextLine,
10         MoveToPreviousLine, MoveToRow, MoveUp, RestorePosition, SavePosition, Show,
11     },
12     ExecutableCommand,
13 };
14 
15 use crate::config::appconfig::LineSetting;
16 
17 use super::{
18     buffer::{EditBuffer, LineBuffer},
19     style::StyleManager,
20     term_io::TermIO,
21     terminal::TermManager,
22     ui::uicore::{CONTENT_WINSIZE, DEF_STYLE, WINSIZE},
23 };
24 
25 struct CursorManager;
26 
27 #[allow(dead_code)]
28 impl CursorManager {
29     #[inline]
move_to(x: u16, y: u16) -> io::Result<()>30     pub fn move_to(x: u16, y: u16) -> io::Result<()> {
31         stdout().execute(MoveTo(x, y)).unwrap().flush()
32     }
33 
34     #[inline]
move_to_nextline(lines: u16) -> io::Result<()>35     pub fn move_to_nextline(lines: u16) -> io::Result<()> {
36         stdout().execute(MoveToNextLine(lines)).unwrap().flush()
37     }
38 
39     #[inline]
move_to_previous_line(lines: u16) -> io::Result<()>40     pub fn move_to_previous_line(lines: u16) -> io::Result<()> {
41         stdout().execute(MoveToPreviousLine(lines)).unwrap().flush()
42     }
43 
44     #[inline]
move_to_columu(col: u16) -> io::Result<()>45     pub fn move_to_columu(col: u16) -> io::Result<()> {
46         stdout().execute(MoveToColumn(col)).unwrap().flush()
47     }
48 
49     #[inline]
move_to_row(row: u16) -> io::Result<()>50     pub fn move_to_row(row: u16) -> io::Result<()> {
51         stdout().execute(MoveToRow(row)).unwrap().flush()
52     }
53 
54     #[inline]
move_up(count: u16) -> io::Result<()>55     pub fn move_up(count: u16) -> io::Result<()> {
56         stdout().execute(MoveUp(count)).unwrap().flush()
57     }
58 
59     #[inline]
move_down(count: u16) -> io::Result<()>60     pub fn move_down(count: u16) -> io::Result<()> {
61         stdout().execute(MoveDown(count)).unwrap().flush()
62     }
63 
64     #[inline]
move_left(count: u16) -> io::Result<()>65     pub fn move_left(count: u16) -> io::Result<()> {
66         stdout().execute(MoveLeft(count)).unwrap().flush()
67     }
68 
69     #[inline]
move_right(count: u16) -> io::Result<()>70     pub fn move_right(count: u16) -> io::Result<()> {
71         stdout().execute(MoveRight(count)).unwrap().flush()
72     }
73 
74     #[inline]
save_position() -> io::Result<()>75     pub fn save_position() -> io::Result<()> {
76         stdout().execute(SavePosition).unwrap().flush()
77     }
78 
79     #[inline]
restore_position() -> io::Result<()>80     pub fn restore_position() -> io::Result<()> {
81         stdout().execute(RestorePosition).unwrap().flush()
82     }
83 
84     #[inline]
hide() -> io::Result<()>85     pub fn hide() -> io::Result<()> {
86         stdout().execute(Hide).unwrap().flush()
87     }
88 
89     #[inline]
show() -> io::Result<()>90     pub fn show() -> io::Result<()> {
91         stdout().execute(Show).unwrap().flush()
92     }
93 }
94 
95 #[derive(Debug)]
96 pub struct CursorCrtl {
97     x: u16,
98     y: u16,
99 
100     // 用于处理状态位置
101     stored_x: u16,
102     stored_y: u16,
103 
104     line_prefix_width: u16,
105     store_flag: bool,
106 
107     // 正文模式会输出前缀,这个标志表示是否需要以正文前缀模式调整坐标
108     prefix_mode: bool,
109 
110     line_setting: LineSetting,
111 
112     buf: Arc<EditBuffer>,
113 }
114 
115 #[allow(dead_code)]
116 impl CursorCrtl {
117     pub const PREFIX_COL: u16 = 1;
new(buf: Arc<EditBuffer>, line_setting: LineSetting) -> Self118     pub fn new(buf: Arc<EditBuffer>, line_setting: LineSetting) -> Self {
119         Self {
120             x: 0,
121             y: 0,
122             stored_x: 0,
123             stored_y: 0,
124             store_flag: false,
125             line_prefix_width: Self::PREFIX_COL,
126             prefix_mode: true,
127             line_setting,
128             buf,
129         }
130     }
131 
x(&self) -> u16132     pub fn x(&self) -> u16 {
133         if self.prefix_mode {
134             if self.x < self.line_prefix_width {
135                 return 0;
136             }
137             self.x - self.line_prefix_width
138         } else {
139             self.x
140         }
141     }
142 
y(&self) -> u16143     pub fn y(&self) -> u16 {
144         self.y
145     }
146 
cmd_y(&self) -> u16147     pub fn cmd_y(&self) -> u16 {
148         if self.store_flag {
149             self.stored_y
150         } else {
151             self.y
152         }
153     }
154 
155     #[inline]
set_prefix_mode(&mut self, on: bool)156     pub fn set_prefix_mode(&mut self, on: bool) {
157         self.prefix_mode = on;
158         if on && self.x < self.line_prefix_width {
159             self.x = self.line_prefix_width;
160             self.move_to_columu(0).unwrap();
161         }
162     }
163 
move_to(&mut self, mut x: u16, y: u16) -> io::Result<()>164     pub fn move_to(&mut self, mut x: u16, y: u16) -> io::Result<()> {
165         if self.prefix_mode {
166             x += self.line_prefix_width;
167         }
168         let size = *WINSIZE.read().unwrap();
169         CursorManager::move_to(x, y)?;
170         self.x = (size.cols - 1).min(x);
171         self.y = (size.rows - 1).min(y);
172         Ok(())
173     }
174 
move_to_nextline(&mut self, mut lines: u16) -> io::Result<()>175     pub fn move_to_nextline(&mut self, mut lines: u16) -> io::Result<()> {
176         let size = *WINSIZE.read().unwrap();
177         if self.y + lines >= size.rows {
178             // 向上滚动
179             // 保存位置
180             let pos = self.store_tmp_pos();
181             // 计算需要滚动的行数
182             let offset = self.buf.offset();
183             if offset < lines as usize {
184                 lines = offset as u16;
185             }
186             // 重新设置偏移位置
187             self.buf.set_offset(offset - lines as usize);
188             //翻页并恢复位置
189             TermManager::scroll_up(lines)?;
190             self.restore_tmp_pos(pos)?;
191         }
192 
193         CursorManager::move_to_nextline(lines)?;
194         if self.prefix_mode {
195             self.x = self.line_prefix_width;
196             self.move_to_columu(0)?;
197         } else {
198             self.x = 0;
199         }
200 
201         self.y += lines;
202         Ok(())
203     }
204 
move_to_previous_line(&mut self, mut lines: u16) -> io::Result<()>205     pub fn move_to_previous_line(&mut self, mut lines: u16) -> io::Result<()> {
206         if self.y() < lines {
207             // 溢出,则向下滚动
208 
209             // 保存位置
210             let pos = self.store_tmp_pos();
211             let offset = self.buf.offset();
212             // 计算需要滚动的行数
213             let line_count = self.buf.line_count();
214             if line_count < offset + lines as usize {
215                 lines = (line_count - offset) as u16;
216             }
217             // 重新设置偏移位置
218             self.buf.set_offset(offset + lines as usize);
219             //翻页并恢复位置
220             TermManager::scroll_up(lines)?;
221             self.restore_tmp_pos(pos)?;
222         }
223 
224         CursorManager::move_to_previous_line(lines)?;
225 
226         self.y -= lines;
227         if self.prefix_mode {
228             self.x = self.line_prefix_width;
229             self.move_to_columu(0)?;
230         } else {
231             self.x = 0;
232         }
233         Ok(())
234     }
235 
move_to_columu(&mut self, mut col: u16) -> io::Result<()>236     pub fn move_to_columu(&mut self, mut col: u16) -> io::Result<()> {
237         if self.prefix_mode {
238             col += self.line_prefix_width;
239         }
240         let size = *WINSIZE.read().unwrap();
241         CursorManager::move_to_columu(col)?;
242         self.x = (size.cols - 1).min(col);
243         Ok(())
244     }
245 
move_to_row(&mut self, row: u16) -> io::Result<()>246     pub fn move_to_row(&mut self, row: u16) -> io::Result<()> {
247         let size = *WINSIZE.read().unwrap();
248         CursorManager::move_to_row(row)?;
249         self.y = (size.rows - 1).min(row);
250         Ok(())
251     }
252 
move_up(&mut self, count: u16) -> io::Result<()>253     pub fn move_up(&mut self, count: u16) -> io::Result<()> {
254         CursorManager::move_up(count)?;
255         self.y -= count;
256 
257         Ok(())
258     }
259 
move_down(&mut self, count: u16) -> io::Result<()>260     pub fn move_down(&mut self, count: u16) -> io::Result<()> {
261         CursorManager::move_down(count)?;
262 
263         self.y += count;
264         Ok(())
265     }
266 
move_left(&mut self, count: u16) -> io::Result<()>267     pub fn move_left(&mut self, count: u16) -> io::Result<()> {
268         // 如果当前光标位置小于或等于行前缀宽度,或者移动的距离大于当前光标位置,则直接移动到行前缀末尾
269         if self.x <= self.line_prefix_width || count > self.x {
270             return self.move_to_columu(0);
271         }
272 
273         // 如果启用了前缀模式且光标在前缀区域内,不进行移动
274         if self.prefix_mode && self.x <= self.line_prefix_width {
275             return Ok(());
276         }
277 
278         // 计算实际移动的距离
279         let actual_move = if count > self.x - self.line_prefix_width {
280             self.x - self.line_prefix_width
281         } else {
282             count
283         };
284 
285         // 执行光标左移操作
286         CursorManager::move_left(actual_move)?;
287 
288         // 更新光标位置
289         self.x -= actual_move;
290 
291         Ok(())
292     }
293 
move_right(&mut self, count: u16) -> io::Result<()>294     pub fn move_right(&mut self, count: u16) -> io::Result<()> {
295         let mut linesize = self.buf.get_linesize(self.y()) - 1;
296         let mut size = *WINSIZE.read().unwrap();
297         if self.prefix_mode {
298             size.cols -= self.line_prefix_width;
299             linesize += self.line_prefix_width;
300         }
301         if self.x == size.cols - 1 {
302             return Ok(());
303         }
304 
305         if self.x + count > linesize {
306             CursorManager::move_to_columu(linesize)?;
307             self.x = linesize;
308         } else {
309             CursorManager::move_right(count)?;
310             self.x += count;
311         }
312 
313         Ok(())
314     }
315 
write<D: Display>(&mut self, str: D) -> io::Result<()>316     pub fn write<D: Display>(&mut self, str: D) -> io::Result<()> {
317         let str = str.to_string();
318 
319         let ss = str.split_terminator(|x| x == '\n').collect::<Vec<&str>>();
320         for s in ss {
321             self.write_line(s)?;
322         }
323         Ok(())
324     }
325 
write_line(&mut self, str: &str) -> io::Result<()>326     fn write_line(&mut self, str: &str) -> io::Result<()> {
327         let len = str.len() as u16;
328 
329         let mut size = *WINSIZE.read().unwrap();
330 
331         if self.prefix_mode {
332             size.cols -= self.line_prefix_width;
333         }
334 
335         if self.x + len > size.cols {
336             let ss = str.split_at((size.cols - self.x) as usize);
337             TermIO::write_str(ss.0)?;
338             self.move_to_nextline(1)?;
339             self.write_line(ss.1)?;
340         } else {
341             TermIO::write_str(str)?;
342             if str.ends_with(|x| x == '\n') {
343                 self.move_to_nextline(1)?;
344             } else {
345                 self.x += str.len() as u16;
346             }
347         }
348 
349         Ok(())
350     }
351 
write_with_pos<D: Display>( &mut self, str: D, x: u16, y: u16, stroe: bool, ) -> io::Result<()>352     pub fn write_with_pos<D: Display>(
353         &mut self,
354         str: D,
355         x: u16,
356         y: u16,
357         stroe: bool,
358     ) -> io::Result<()> {
359         let mut pos = (0, 0);
360         if stroe {
361             pos = self.store_tmp_pos();
362         }
363         self.move_to(x, y)?;
364         self.write(str)?;
365         if stroe {
366             self.restore_tmp_pos(pos)?;
367         }
368         Ok(())
369     }
370 
store_pos(&mut self)371     pub fn store_pos(&mut self) {
372         if self.store_flag {
373             panic!("Stored val doesn't restore")
374         }
375         self.stored_x = self.x;
376         self.stored_y = self.y;
377         self.store_flag = true;
378     }
379 
restore_pos(&mut self) -> io::Result<()>380     pub fn restore_pos(&mut self) -> io::Result<()> {
381         if !self.store_flag {
382             panic!("No val stored")
383         }
384         self.x = self.stored_x;
385         self.y = self.stored_y;
386         self.store_flag = false;
387         CursorManager::move_to(self.stored_x, self.stored_y)
388     }
389 
390     #[inline]
store_tmp_pos(&mut self) -> (u16, u16)391     pub fn store_tmp_pos(&mut self) -> (u16, u16) {
392         (self.x(), self.y())
393     }
394 
restore_tmp_pos(&mut self, pos: (u16, u16)) -> io::Result<()>395     pub fn restore_tmp_pos(&mut self, pos: (u16, u16)) -> io::Result<()> {
396         self.move_to(pos.0, pos.1)
397     }
398 
399     /// 更新前缀列
update_line_prefix( &mut self, content: &Vec<LineBuffer>, start: u16, number_len: usize, ) -> io::Result<()>400     pub fn update_line_prefix(
401         &mut self,
402         content: &Vec<LineBuffer>,
403         start: u16,
404         number_len: usize,
405     ) -> io::Result<()> {
406         let startline = self.buf.offset() + 1;
407         let size = *CONTENT_WINSIZE.read().unwrap();
408         let max_line = startline + size.rows as usize;
409 
410         // 先关闭prefix模式
411         self.set_prefix_mode(false);
412 
413         // 绝对坐标
414         let (x, y) = (self.x(), self.y());
415 
416         // 更新第一列flags
417         for (num, line) in content.iter().enumerate() {
418             // 设置颜色
419             StyleManager::set_background_color(self.line_setting.line_num.background)?;
420             StyleManager::set_foreground_color(self.line_setting.line_num.frontground)?;
421             self.move_to(0, start + num as u16)?;
422             let flags = line.flags;
423             flags.set_style()?;
424             self.write("~")?;
425             StyleManager::reset_color()?;
426         }
427 
428         // 更新页面行号
429         if self.line_setting.line_num.enable {
430             let len = number_len + 2;
431             self.line_prefix_width = len as u16 + Self::PREFIX_COL;
432 
433             // 设置颜色
434             StyleManager::set_background_color(self.line_setting.line_num.background)?;
435             StyleManager::set_foreground_color(self.line_setting.line_num.frontground)?;
436             for line in startline..max_line {
437                 self.move_to(Self::PREFIX_COL, (line - startline) as u16)?;
438                 let mut prefix = line.to_string();
439 
440                 prefix.insert(0, ' ');
441                 unsafe {
442                     let data = prefix.as_mut_vec();
443                     data.resize(len, ' ' as u8);
444                 };
445 
446                 self.write(prefix)?;
447             }
448             StyleManager::reset_color()?;
449         }
450         // 恢复绝对坐标
451         self.move_to(x, y)?;
452 
453         self.set_prefix_mode(true);
454 
455         Ok(())
456     }
457 
clear_current_line(&mut self) -> io::Result<()>458     pub fn clear_current_line(&mut self) -> io::Result<()> {
459         if self.prefix_mode {
460             let tmp = self.x();
461             self.move_to_columu(0)?;
462             TermManager::clear_until_new_line()?;
463             self.move_to_columu(tmp)
464         } else {
465             TermManager::clear_current_line()
466         }
467     }
468 
highlight(&mut self, last_line: Option<u16>) -> io::Result<()>469     pub fn highlight(&mut self, last_line: Option<u16>) -> io::Result<()> {
470         if !self.line_setting.highlight.enable {
471             return Ok(());
472         }
473         DEF_STYLE.read().unwrap().set_content_style()?;
474 
475         if last_line.is_some() {
476             let last_line = last_line.unwrap();
477             // 清除上一行高光
478             let pos = self.store_tmp_pos();
479             self.move_to(0, last_line)?;
480             self.clear_current_line()?;
481             self.write(String::from_utf8_lossy(&self.buf.get_line(last_line)))?;
482             self.restore_tmp_pos(pos)?;
483         }
484 
485         let pos = self.store_tmp_pos();
486         // 设置高光
487         StyleManager::set_background_color(self.line_setting.highlight.color)?;
488         self.clear_current_line()?;
489         self.move_to_columu(0)?;
490         self.write(String::from_utf8_lossy(&self.buf.get_line(self.y())))?;
491         self.restore_tmp_pos(pos)?;
492 
493         Ok(())
494     }
495 }
496