xref: /NovaShell/src/shell/printer.rs (revision b0dea7c16fca9b46f663bf62b95934b09704b896)
1 use std::{
2     cell::RefCell,
3     fmt,
4     io::{self, stdout, Write},
5     ops::Deref,
6     print,
7     rc::Rc,
8 };
9 
10 use colored::Colorize;
11 
12 pub struct Printer {
13     /// 提示语
14     pub prompt: Prompt,
15     /// 缓存区,记录当前显示的内容
16     pub buf: Rc<RefCell<Vec<u8>>>,
17     /// 光标位置(不包括提示语)
18     pub cursor: usize,
19 }
20 
21 impl Printer {
22     pub fn new(bytes: &Rc<RefCell<Vec<u8>>>) -> Self {
23         Printer {
24             prompt: Prompt {
25                 computer_name: "DragonOS".to_string(),
26                 user_name: "root".to_string(),
27                 path: std::env::current_dir()
28                     .expect("Error getting current directory")
29                     .to_str()
30                     .unwrap()
31                     .to_string(),
32             },
33             buf: Rc::clone(bytes),
34             cursor: 0,
35         }
36     }
37 
38     /// 读取输入前初始化信息
39     pub fn init_before_readline(&mut self) {
40         self.buf = Rc::new(RefCell::new(Vec::new()));
41         self.prompt.update_path();
42         self.print_prompt();
43         self.cursor = 0;
44     }
45 
46     pub fn print_prompt(&self) {
47         print!("{}", self.prompt);
48         stdout().flush().unwrap();
49     }
50 
51     /// 在光标处插入字符串
52     pub fn insert(&mut self, bytes: &[u8]) {
53         // 记录光标距离末尾的长度,用于后续光标复位
54         let len_to_end = self.buf.deref().borrow().len() - self.cursor;
55 
56         // 在buf中插入内容
57         let mut buf = self.buf.deref().borrow_mut();
58         buf.splice(self.cursor..self.cursor, bytes.iter().cloned());
59 
60         // 打印cursor后面的内容,此时屏幕光标在末尾
61         print!(
62             "{}",
63             String::from_utf8(buf[self.cursor..].to_vec()).unwrap()
64         );
65 
66         // 移回光标
67         if len_to_end > 0 {
68             crossterm::execute!(
69                 io::stdout(),
70                 crossterm::cursor::MoveLeft(len_to_end.try_into().unwrap())
71             )
72             .unwrap();
73         }
74         self.cursor += bytes.len();
75 
76         stdout().flush().unwrap();
77     }
78 
79     /// 删除下标为[cursor,cursor + len)的字符,光标位置不变
80     pub fn delete(&mut self, len: usize) {
81         let cursor = self.cursor;
82         let buf_len = self.buf.deref().borrow().len();
83 
84         // 判断最大下标是否越界
85         if cursor + len - 1 < buf_len {
86             // 在buf中删除内容
87             self.buf.deref().borrow_mut().drain(cursor..cursor + len);
88 
89             // 直接打印删除范围之后的内容
90             print!(
91                 "{}",
92                 String::from_utf8(self.buf.deref().borrow()[self.cursor..].to_vec()).unwrap()
93             );
94 
95             // 打印len个空格覆盖遗留的内容,此时屏幕光标下标恰好为原buf长度
96             print!("{}", " ".repeat(len));
97 
98             // 屏幕光标移回原位
99             crossterm::execute!(
100                 io::stdout(),
101                 crossterm::cursor::MoveLeft((buf_len - cursor).try_into().unwrap())
102             )
103             .unwrap();
104             stdout().flush().unwrap();
105         }
106     }
107 
108     pub fn backspace(&mut self) {
109         if self.cursor > 0 {
110             self.cursor_left(1);
111             self.delete(1);
112         }
113     }
114 
115     pub fn cursor_left(&mut self, len: usize) {
116         if self.cursor > 0 {
117             crossterm::execute!(
118                 io::stdout(),
119                 crossterm::cursor::MoveLeft(len.try_into().unwrap())
120             )
121             .unwrap();
122             self.cursor -= len;
123         }
124     }
125 
126     pub fn cursor_right(&mut self, len: usize) {
127         let buf = self.buf.deref().borrow();
128         if self.cursor < buf.len() {
129             crossterm::execute!(
130                 io::stdout(),
131                 crossterm::cursor::MoveRight(len.try_into().unwrap())
132             )
133             .unwrap();
134             self.cursor += len;
135         }
136     }
137 
138     pub fn home(&mut self) {
139         self.cursor_left(self.cursor);
140     }
141 
142     pub fn end(&mut self) {
143         let buf_len = self.buf.deref().borrow().len();
144         self.cursor_right(buf_len - self.cursor);
145     }
146 
147     /// 将命令行的内容修改为新的内容
148     pub fn change_line(&mut self, new_buf: &Rc<RefCell<Vec<u8>>>) {
149         // 移动到开头
150         self.home();
151 
152         // 打印新的字符串
153         print!(
154             "{}",
155             String::from_utf8(new_buf.deref().borrow()[..].to_vec()).unwrap()
156         );
157 
158         // 如果新字符串长度比旧的短,后面会有残留,用空格覆盖
159         let old_buf_len = self.buf.deref().borrow().len();
160         let new_buf_len = new_buf.deref().borrow().len();
161         if new_buf_len < old_buf_len {
162             let remain_len = old_buf_len - new_buf_len;
163             print!("{}", " ".repeat(remain_len));
164             crossterm::execute!(
165                 io::stdout(),
166                 crossterm::cursor::MoveLeft(remain_len.try_into().unwrap())
167             )
168             .unwrap();
169         }
170 
171         self.cursor = new_buf_len;
172         self.buf = Rc::clone(new_buf);
173         stdout().flush().unwrap();
174     }
175 }
176 
177 pub struct Prompt {
178     user_name: String,
179     computer_name: String,
180     path: String,
181 }
182 
183 impl Prompt {
184     pub fn len(&self) -> usize {
185         format!("{}@{}:{}$ ", self.user_name, self.computer_name, self.path).len()
186     }
187 
188     pub fn update_path(&mut self) {
189         self.path = std::env::current_dir()
190             .unwrap()
191             .to_str()
192             .unwrap()
193             .to_string();
194     }
195 }
196 
197 impl fmt::Display for Prompt {
198     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199         write!(
200             f,
201             "{}:{}$ ",
202             format!("{}@{}", self.user_name, self.computer_name).bright_green(),
203             self.path.bright_cyan()
204         )
205     }
206 }
207 
208 // 测试终端颜色显示效果
209 #[allow(dead_code)]
210 pub fn _print_color_example() {
211     let example = "abcdefghijklmnopqrstuvwxyz";
212     println!("{}", example.bright_black());
213     println!("{}", example.bright_blue());
214     println!("{}", example.bright_cyan());
215     println!("{}", example.bright_green());
216     println!("{}", example.bright_magenta());
217     println!("{}", example.bright_purple());
218     println!("{}", example.bright_red());
219     println!("{}", example.bright_white());
220     println!("{}", example.bright_yellow());
221     println!("{}", example.black());
222     println!("{}", example.blue());
223     println!("{}", example.cyan());
224     println!("{}", example.green());
225     println!("{}", example.magenta());
226     println!("{}", example.purple());
227     println!("{}", example.red());
228     println!("{}", example.white());
229     println!("{}", example.yellow());
230 }
231