xref: /Held/src/utils/cursor.rs (revision 984a200e159c143eb730a2df362731fe1a62fe01)
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]
30     pub fn move_to(x: u16, y: u16) -> io::Result<()> {
31         stdout().execute(MoveTo(x, y)).unwrap().flush()
32     }
33 
34     #[inline]
35     pub fn move_to_nextline(lines: u16) -> io::Result<()> {
36         stdout().execute(MoveToNextLine(lines)).unwrap().flush()
37     }
38 
39     #[inline]
40     pub fn move_to_previous_line(lines: u16) -> io::Result<()> {
41         stdout().execute(MoveToPreviousLine(lines)).unwrap().flush()
42     }
43 
44     #[inline]
45     pub fn move_to_columu(col: u16) -> io::Result<()> {
46         stdout().execute(MoveToColumn(col)).unwrap().flush()
47     }
48 
49     #[inline]
50     pub fn move_to_row(row: u16) -> io::Result<()> {
51         stdout().execute(MoveToRow(row)).unwrap().flush()
52     }
53 
54     #[inline]
55     pub fn move_up(count: u16) -> io::Result<()> {
56         stdout().execute(MoveUp(count)).unwrap().flush()
57     }
58 
59     #[inline]
60     pub fn move_down(count: u16) -> io::Result<()> {
61         stdout().execute(MoveDown(count)).unwrap().flush()
62     }
63 
64     #[inline]
65     pub fn move_left(count: u16) -> io::Result<()> {
66         stdout().execute(MoveLeft(count)).unwrap().flush()
67     }
68 
69     #[inline]
70     pub fn move_right(count: u16) -> io::Result<()> {
71         stdout().execute(MoveRight(count)).unwrap().flush()
72     }
73 
74     #[inline]
75     pub fn save_position() -> io::Result<()> {
76         stdout().execute(SavePosition).unwrap().flush()
77     }
78 
79     #[inline]
80     pub fn restore_position() -> io::Result<()> {
81         stdout().execute(RestorePosition).unwrap().flush()
82     }
83 
84     #[inline]
85     pub fn hide() -> io::Result<()> {
86         stdout().execute(Hide).unwrap().flush()
87     }
88 
89     #[inline]
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;
118     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 
132     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 
143     pub fn y(&self) -> u16 {
144         self.y
145     }
146 
147     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]
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 
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 
175     pub fn move_to_nextline(&mut self, lines: u16) -> io::Result<()> {
176         let size = *WINSIZE.read().unwrap();
177         if self.y + lines >= size.rows {
178             // 向上滚动
179             todo!()
180         }
181 
182         CursorManager::move_to_nextline(lines)?;
183         if self.prefix_mode {
184             self.x = self.line_prefix_width;
185             self.move_to_columu(0)?;
186         } else {
187             self.x = 0;
188         }
189 
190         self.y += lines;
191         Ok(())
192     }
193 
194     pub fn move_to_previous_line(&mut self, lines: u16) -> io::Result<()> {
195         let size = *WINSIZE.read().unwrap();
196 
197         if self.y() - lines > size.rows {
198             // 溢出,则向下滚动
199             todo!()
200         }
201 
202         CursorManager::move_to_previous_line(lines)?;
203 
204         self.y -= lines;
205         if self.prefix_mode {
206             self.x = self.line_prefix_width;
207             self.move_to_columu(0)?;
208         } else {
209             self.x = 0;
210         }
211         Ok(())
212     }
213 
214     pub fn move_to_columu(&mut self, mut col: u16) -> io::Result<()> {
215         if self.prefix_mode {
216             col += self.line_prefix_width;
217         }
218         let size = *WINSIZE.read().unwrap();
219         CursorManager::move_to_columu(col)?;
220         self.x = (size.cols - 1).min(col);
221         Ok(())
222     }
223 
224     pub fn move_to_row(&mut self, row: u16) -> io::Result<()> {
225         let size = *WINSIZE.read().unwrap();
226         CursorManager::move_to_row(row)?;
227         self.y = (size.rows - 1).min(row);
228         Ok(())
229     }
230 
231     pub fn move_up(&mut self, count: u16) -> io::Result<()> {
232         CursorManager::move_up(count)?;
233         self.y -= count;
234 
235         Ok(())
236     }
237 
238     pub fn move_down(&mut self, count: u16) -> io::Result<()> {
239         CursorManager::move_down(count)?;
240 
241         self.y += count;
242         Ok(())
243     }
244 
245     pub fn move_left(&mut self, mut count: u16) -> io::Result<()> {
246         if count > self.x {
247             return self.move_to_columu(0);
248         }
249         if self.prefix_mode {
250             if self.x == self.line_prefix_width - 1 {
251                 return Ok(());
252             }
253             if self.x - count < self.line_prefix_width {
254                 return self.move_to_columu(0);
255             }
256         }
257         if self.x == 0 {
258             return Ok(());
259         }
260         if count > self.x {
261             count = self.x - self.line_prefix_width
262         }
263         CursorManager::move_left(count)?;
264 
265         if count > self.x {
266             self.x = self.line_prefix_width - 1;
267         } else {
268             self.x -= count;
269         }
270 
271         Ok(())
272     }
273 
274     pub fn move_right(&mut self, count: u16) -> io::Result<()> {
275         let mut linesize = self.buf.get_linesize(self.y()) - 1;
276         let mut size = *WINSIZE.read().unwrap();
277         if self.prefix_mode {
278             size.cols -= self.line_prefix_width;
279             linesize += self.line_prefix_width;
280         }
281         if self.x == size.cols - 1 {
282             return Ok(());
283         }
284 
285         if self.x + count > linesize {
286             CursorManager::move_to_columu(linesize)?;
287             self.x = linesize;
288         } else {
289             CursorManager::move_right(count)?;
290             self.x += count;
291         }
292 
293         Ok(())
294     }
295 
296     pub fn write<D: Display>(&mut self, str: D) -> io::Result<()> {
297         let str = str.to_string();
298 
299         let ss = str.split_terminator(|x| x == '\n').collect::<Vec<&str>>();
300         for s in ss {
301             self.write_line(s)?;
302         }
303         Ok(())
304     }
305 
306     fn write_line(&mut self, str: &str) -> io::Result<()> {
307         let len = str.len() as u16;
308 
309         let mut size = *WINSIZE.read().unwrap();
310 
311         if self.prefix_mode {
312             size.cols -= self.line_prefix_width;
313         }
314 
315         if self.x + len > size.cols {
316             let ss = str.split_at((size.cols - self.x) as usize);
317             TermIO::write_str(ss.0)?;
318             self.move_to_nextline(1)?;
319             self.write_line(ss.1)?;
320         } else {
321             TermIO::write_str(str)?;
322             if str.ends_with(|x| x == '\n') {
323                 self.move_to_nextline(1)?;
324             } else {
325                 self.x += str.len() as u16;
326             }
327         }
328 
329         Ok(())
330     }
331 
332     pub fn write_with_pos<D: Display>(
333         &mut self,
334         str: D,
335         x: u16,
336         y: u16,
337         stroe: bool,
338     ) -> io::Result<()> {
339         let mut pos = (0, 0);
340         if stroe {
341             pos = self.store_tmp_pos();
342         }
343         self.move_to(x, y)?;
344         self.write(str)?;
345         if stroe {
346             self.restore_tmp_pos(pos)?;
347         }
348         Ok(())
349     }
350 
351     pub fn store_pos(&mut self) {
352         if self.store_flag {
353             panic!("Stored val doesn't restore")
354         }
355         self.stored_x = self.x;
356         self.stored_y = self.y;
357         self.store_flag = true;
358     }
359 
360     pub fn restore_pos(&mut self) -> io::Result<()> {
361         if !self.store_flag {
362             panic!("No val stored")
363         }
364         self.x = self.stored_x;
365         self.y = self.stored_y;
366         self.store_flag = false;
367         CursorManager::move_to(self.stored_x, self.stored_y)
368     }
369 
370     #[inline]
371     pub fn store_tmp_pos(&mut self) -> (u16, u16) {
372         (self.x(), self.y())
373     }
374 
375     pub fn restore_tmp_pos(&mut self, pos: (u16, u16)) -> io::Result<()> {
376         self.move_to(pos.0, pos.1)
377     }
378 
379     /// 更新前缀列
380     pub fn update_line_prefix(
381         &mut self,
382         content: &Vec<LineBuffer>,
383         start: u16,
384         number_len: usize,
385     ) -> io::Result<()> {
386         let startline = self.buf.offset() + 1;
387         let size = *CONTENT_WINSIZE.read().unwrap();
388         let max_line = startline + size.rows as usize;
389 
390         // 先关闭prefix模式
391         self.set_prefix_mode(false);
392 
393         // 绝对坐标
394         let (x, y) = (self.x(), self.y());
395 
396         // 更新第一列flags
397         for (num, line) in content.iter().enumerate() {
398             // 设置颜色
399             StyleManager::set_background_color(self.line_setting.line_num.background)?;
400             StyleManager::set_foreground_color(self.line_setting.line_num.frontground)?;
401             self.move_to(0, start + num as u16)?;
402             let flags = line.flags;
403             flags.set_style()?;
404             self.write("~")?;
405             StyleManager::reset_color()?;
406         }
407 
408         // 更新页面行号
409         if self.line_setting.line_num.enable {
410             let len = number_len + 2;
411             self.line_prefix_width = len as u16 + Self::PREFIX_COL;
412 
413             // 设置颜色
414             StyleManager::set_background_color(self.line_setting.line_num.background)?;
415             StyleManager::set_foreground_color(self.line_setting.line_num.frontground)?;
416             for line in startline..max_line {
417                 self.move_to(Self::PREFIX_COL, (line - startline) as u16)?;
418                 let mut prefix = line.to_string();
419 
420                 prefix.insert(0, ' ');
421                 unsafe {
422                     let data = prefix.as_mut_vec();
423                     data.resize(len, ' ' as u8);
424                 };
425 
426                 self.write(prefix)?;
427             }
428             StyleManager::reset_color()?;
429         }
430         // 恢复绝对坐标
431         self.move_to(x, y)?;
432 
433         self.set_prefix_mode(true);
434 
435         Ok(())
436     }
437 
438     pub fn clear_current_line(&mut self) -> io::Result<()> {
439         if self.prefix_mode {
440             let tmp = self.x();
441             self.move_to_columu(0)?;
442             TermManager::clear_until_new_line()?;
443             self.move_to_columu(tmp)
444         } else {
445             TermManager::clear_current_line()
446         }
447     }
448 
449     pub fn highlight(&mut self, last_line: Option<u16>) -> io::Result<()> {
450         if !self.line_setting.highlight.enable {
451             return Ok(());
452         }
453         DEF_STYLE.read().unwrap().set_content_style()?;
454 
455         if last_line.is_some() {
456             let last_line = last_line.unwrap();
457             // 清除上一行高光
458             let pos = self.store_tmp_pos();
459             self.move_to(0, last_line)?;
460             self.clear_current_line()?;
461             self.write(String::from_utf8_lossy(&self.buf.get_line(last_line)))?;
462             self.restore_tmp_pos(pos)?;
463         }
464 
465         let pos = self.store_tmp_pos();
466         // 设置高光
467         StyleManager::set_background_color(self.line_setting.highlight.color)?;
468         self.clear_current_line()?;
469         self.move_to_columu(0)?;
470         self.write(String::from_utf8_lossy(&self.buf.get_line(self.y())))?;
471         self.restore_tmp_pos(pos)?;
472 
473         Ok(())
474     }
475 }
476