xref: /Held/src/utils/cursor.rs (revision 7d5806d5b291a1c82166840048ed0c0986d637ec)
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, 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 
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 
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 
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 
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 
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 
267     pub fn move_left(&mut self, count: u16) -> io::Result<()> {
268         let result = match self.x {
269             x if x == 0 => Ok(()),
270             x if x < count => self.move_to_columu(0),
271             x => match self.prefix_mode {
272                 true if x == self.line_prefix_width - 1 => Ok(()),
273                 true if x - count < self.line_prefix_width => self.move_to_columu(0),
274                 _ => {
275                     self.x -= count;
276                     self.move_to_columu(x - count)
277                 }
278             },
279         };
280 
281         result
282     }
283 
284     pub fn move_right(&mut self, count: u16) -> io::Result<()> {
285         let mut linesize = self.buf.get_linesize(self.y()) - 1;
286         let mut size = *WINSIZE.read().unwrap();
287         if self.prefix_mode {
288             size.cols -= self.line_prefix_width;
289             linesize += self.line_prefix_width;
290         }
291         if self.x == size.cols - 1 {
292             return Ok(());
293         }
294 
295         if self.x + count > linesize {
296             CursorManager::move_to_columu(linesize)?;
297             self.x = linesize;
298         } else {
299             CursorManager::move_right(count)?;
300             self.x += count;
301         }
302 
303         Ok(())
304     }
305 
306     pub fn write<D: Display>(&mut self, str: D) -> io::Result<()> {
307         let str = str.to_string();
308 
309         let ss = str.split_terminator(|x| x == '\n').collect::<Vec<&str>>();
310         for s in ss {
311             self.write_line(s)?;
312         }
313         Ok(())
314     }
315 
316     fn write_line(&mut self, str: &str) -> io::Result<()> {
317         let len = str.len() as u16;
318 
319         let mut size = *WINSIZE.read().unwrap();
320 
321         if self.prefix_mode {
322             size.cols -= self.line_prefix_width;
323         }
324 
325         if self.x + len > size.cols {
326             let ss = str.split_at((size.cols - self.x) as usize);
327             TermIO::write_str(ss.0)?;
328             self.move_to_nextline(1)?;
329             self.write_line(ss.1)?;
330         } else {
331             TermIO::write_str(str)?;
332             if str.ends_with(|x| x == '\n') {
333                 self.move_to_nextline(1)?;
334             } else {
335                 self.x += str.len() as u16;
336             }
337         }
338 
339         Ok(())
340     }
341 
342     pub fn write_with_pos<D: Display>(
343         &mut self,
344         str: D,
345         x: u16,
346         y: u16,
347         stroe: bool,
348     ) -> io::Result<()> {
349         let mut pos = (0, 0);
350         if stroe {
351             pos = self.store_tmp_pos();
352         }
353         self.move_to(x, y)?;
354         self.write(str)?;
355         if stroe {
356             self.restore_tmp_pos(pos)?;
357         }
358         Ok(())
359     }
360 
361     pub fn store_pos(&mut self) {
362         if self.store_flag {
363             panic!("Stored val doesn't restore")
364         }
365         self.stored_x = self.x;
366         self.stored_y = self.y;
367         self.store_flag = true;
368     }
369 
370     pub fn restore_pos(&mut self) -> io::Result<()> {
371         if !self.store_flag {
372             panic!("No val stored")
373         }
374         self.x = self.stored_x;
375         self.y = self.stored_y;
376         self.store_flag = false;
377         CursorManager::move_to(self.stored_x, self.stored_y)
378     }
379 
380     #[inline]
381     pub fn store_tmp_pos(&mut self) -> (u16, u16) {
382         (self.x(), self.y())
383     }
384 
385     pub fn restore_tmp_pos(&mut self, pos: (u16, u16)) -> io::Result<()> {
386         self.move_to(pos.0, pos.1)
387     }
388 
389     /// 更新前缀列
390     pub fn update_line_prefix(
391         &mut self,
392         content: &Vec<LineBuffer>,
393         start: u16,
394         number_len: usize,
395     ) -> io::Result<()> {
396         let startline = self.buf.offset() + 1;
397         let size = *CONTENT_WINSIZE.read().unwrap();
398         let max_line = startline + size.rows as usize;
399 
400         // 先关闭prefix模式
401         self.set_prefix_mode(false);
402 
403         // 绝对坐标
404         let (x, y) = (self.x(), self.y());
405 
406         // 更新第一列flags
407         for (num, line) in content.iter().enumerate() {
408             // 设置颜色
409             StyleManager::set_background_color(self.line_setting.line_num.background)?;
410             StyleManager::set_foreground_color(self.line_setting.line_num.frontground)?;
411             self.move_to(0, start + num as u16)?;
412             let flags = line.flags;
413             flags.set_style()?;
414             self.write("~")?;
415             StyleManager::reset_color()?;
416         }
417 
418         // 更新页面行号
419         if self.line_setting.line_num.enable {
420             let len = number_len + 2;
421             self.line_prefix_width = len as u16 + Self::PREFIX_COL;
422 
423             // 设置颜色
424             StyleManager::set_background_color(self.line_setting.line_num.background)?;
425             StyleManager::set_foreground_color(self.line_setting.line_num.frontground)?;
426             for line in startline..max_line {
427                 self.move_to(Self::PREFIX_COL, (line - startline) as u16)?;
428                 let mut prefix = line.to_string();
429 
430                 prefix.insert(0, ' ');
431                 unsafe {
432                     let data = prefix.as_mut_vec();
433                     data.resize(len, ' ' as u8);
434                 };
435 
436                 self.write(prefix)?;
437             }
438             StyleManager::reset_color()?;
439         }
440         // 恢复绝对坐标
441         self.move_to(x, y)?;
442 
443         self.set_prefix_mode(true);
444 
445         Ok(())
446     }
447 
448     pub fn clear_current_line(&mut self) -> io::Result<()> {
449         if self.prefix_mode {
450             let tmp = self.x();
451             self.move_to_columu(0)?;
452             TermManager::clear_until_new_line()?;
453             self.move_to_columu(tmp)
454         } else {
455             TermManager::clear_current_line()
456         }
457     }
458 
459     pub fn highlight(&mut self, last_line: Option<u16>) -> io::Result<()> {
460         if !self.line_setting.highlight.enable {
461             return Ok(());
462         }
463         DEF_STYLE.read().unwrap().set_content_style()?;
464 
465         if last_line.is_some() {
466             let last_line = last_line.unwrap();
467             // 清除上一行高光
468             let pos = self.store_tmp_pos();
469             self.move_to(0, last_line)?;
470             self.clear_current_line()?;
471             self.write(String::from_utf8_lossy(&self.buf.get_line(last_line)))?;
472             self.restore_tmp_pos(pos)?;
473         }
474 
475         let pos = self.store_tmp_pos();
476         // 设置高光
477         StyleManager::set_background_color(self.line_setting.highlight.color)?;
478         self.clear_current_line()?;
479         self.move_to_columu(0)?;
480         self.write(String::from_utf8_lossy(&self.buf.get_line(self.y())))?;
481         self.restore_tmp_pos(pos)?;
482 
483         Ok(())
484     }
485 }
486