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