xref: /NovaShell/src/shell/mod.rs (revision dcf45035c1cd8e9ca847b56b3bd65f53a4eda8b6)
1 use core::fmt;
2 use std::{
3     cell::RefCell,
4     fs::{self, File, OpenOptions},
5     io::{self, stdout, BufRead, BufReader, Read, Write},
6     ops::Deref,
7     path::Path,
8     print,
9     rc::Rc,
10     string::String,
11     vec::Vec,
12 };
13 
14 use crate::keycode::{FunctionKeySuffix, SpecialKeycode};
15 
16 use colored::Colorize;
17 use command::{BuildInCmd, Command};
18 
19 pub mod command;
20 
21 pub struct Prompt {
22     user_name: String,
23     computer_name: String,
24     path: String,
25 }
26 
27 impl Prompt {
28     pub fn len(&self) -> usize {
29         format!("{}@{}:{}$ ", self.user_name, self.computer_name, self.path).len()
30     }
31 
32     pub fn update_path(&mut self) {
33         self.path = std::env::current_dir()
34             .unwrap()
35             .to_str()
36             .unwrap()
37             .to_string();
38     }
39 }
40 
41 impl fmt::Display for Prompt {
42     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43         write!(
44             f,
45             "{}:{}$ ",
46             format!("{}@{}", self.user_name, self.computer_name).bright_green(),
47             self.path.bright_cyan()
48         )
49     }
50 }
51 
52 const DEFAULT_HISTORY_COMMANDS_PATH: &str = "/history_commands.txt";
53 
54 pub struct Shell {
55     history_commands: Vec<Rc<RefCell<Vec<u8>>>>,
56     history_path: String,
57     printer: Printer,
58 }
59 
60 impl Shell {
61     pub fn new() -> Shell {
62         let mut shell = Shell {
63             history_commands: Vec::new(),
64             history_path: DEFAULT_HISTORY_COMMANDS_PATH.to_string(),
65             printer: Printer::new(&Rc::new(RefCell::new(Vec::new()))),
66         };
67         shell.read_commands();
68         shell
69     }
70 
71     pub fn current_dir() -> String {
72         std::env::current_dir()
73             .expect("Error getting current directory")
74             .to_str()
75             .unwrap()
76             .to_string()
77     }
78 
79     pub fn chdir(&mut self, new_dir: &String) {
80         let path = Path::new(&new_dir);
81         if let Err(e) = std::env::set_current_dir(&path) {
82             eprintln!("Error changing directory: {}", e);
83         }
84     }
85 
86     pub fn exec(&mut self) {
87         crossterm::terminal::enable_raw_mode().expect("failed to enable raw mode");
88         loop {
89             self.printer.init_before_readline();
90             if self.readline() == 0 {
91                 println!();
92                 break;
93             }
94             let command_bytes = self.printer.buf.borrow().clone();
95             if !command_bytes.is_empty()
96                 && !command_bytes.starts_with(&[b' '])
97                 && command_bytes
98                     != self
99                         .history_commands
100                         .last()
101                         .unwrap_or(&Rc::new(RefCell::new(Vec::new())))
102                         .borrow()
103                         .clone()
104             {
105                 self.history_commands
106                     .push(Rc::new(RefCell::new(command_bytes.clone())));
107                 self.write_commands(&command_bytes);
108             };
109             if !command_bytes.iter().all(|&byte| byte == b' ') {
110                 self.exec_commands_in_line(&command_bytes);
111             }
112         }
113     }
114 
115     fn exec_commands_in_line(&mut self, command_bytes: &Vec<u8>) {
116         let commands = Command::from_strings(String::from_utf8(command_bytes.clone()).unwrap());
117         commands
118             .iter()
119             .for_each(|command| self.exec_command(command));
120     }
121 
122     pub fn read_commands(&mut self) {
123         let mut history = Vec::new();
124         for line in BufReader::new(match File::open(&self.history_path) {
125             Ok(file) => file,
126             Err(_) => File::create(&self.history_path).unwrap(),
127         })
128         .lines()
129         {
130             match line {
131                 Ok(s) => history.push(Rc::new(RefCell::new(s.into_bytes()))),
132                 Err(_) => {
133                     break;
134                 }
135             }
136         }
137         self.history_commands = history;
138     }
139 
140     fn write_commands(&self, command_bytes: &Vec<u8>) {
141         let mut file = OpenOptions::new()
142             .append(true)
143             .open(self.history_path.as_str())
144             .unwrap();
145         file.write_all(&command_bytes)
146             .expect("failed to write history command");
147         file.write_all(&[SpecialKeycode::LF.into()]).unwrap();
148     }
149 
150     fn read_char() -> u8 {
151         let mut buf: [u8; 1] = [0];
152         std::io::stdin().read(&mut buf).expect("read char error");
153         buf[0]
154     }
155 
156     fn readline(&mut self) -> usize {
157         let mut stdout = std::io::stdout();
158         self.history_commands.push(Rc::clone(&self.printer.buf));
159         let mut command_index = self.history_commands.len() - 1;
160         loop {
161             let key = Self::read_char();
162             if let Ok(special_key) = SpecialKeycode::try_from(key) {
163                 match special_key {
164                     SpecialKeycode::FunctionKeyPrefix => {
165                         let key = Self::read_char();
166                         let function_key = FunctionKeySuffix::try_from(key).unwrap();
167                         match function_key {
168                             FunctionKeySuffix::Up => {
169                                 if command_index > 0 {
170                                     command_index -= 1;
171                                     self.printer.change_line(
172                                         self.history_commands.get(command_index).unwrap(),
173                                     );
174                                 }
175                             }
176 
177                             FunctionKeySuffix::Down => {
178                                 if command_index < self.history_commands.len() - 1 {
179                                     command_index += 1;
180                                     self.printer.change_line(
181                                         self.history_commands.get(command_index).unwrap(),
182                                     );
183                                 }
184                             }
185 
186                             FunctionKeySuffix::Left => {
187                                 self.printer.cursor_left();
188                             }
189 
190                             FunctionKeySuffix::Right => {
191                                 self.printer.cursor_right();
192                             }
193 
194                             FunctionKeySuffix::Home => {
195                                 self.printer.home();
196                             }
197 
198                             FunctionKeySuffix::End => {
199                                 self.printer.end();
200                             }
201                         }
202                     }
203 
204                     SpecialKeycode::LF | SpecialKeycode::CR => {
205                         println!();
206                         self.history_commands.pop();
207                         return 1;
208                     }
209 
210                     SpecialKeycode::BackSpace => {
211                         self.printer.backspace();
212                     }
213 
214                     SpecialKeycode::Delete => {
215                         self.printer.delete(1);
216                     }
217 
218                     SpecialKeycode::Tab => {
219                         let mut buf = self.printer.buf.deref().borrow().clone();
220                         buf.truncate(self.printer.cursor);
221                         let str = String::from_utf8(buf.clone()).unwrap();
222                         if buf.len() == 0 || buf.iter().all(|byte| *byte == b' ') {
223                             return 1;
224                         }
225 
226                         let iter = str.chars();
227                         let mut fragments: Vec<String> = Vec::new();
228                         let mut stack: String = String::with_capacity(str.len());
229                         let mut left_quote: char = ' ';
230                         for ch in iter {
231                             //存在未闭合的左引号,此时包括空格的任何字符都加入栈中,直到匹配到右引号
232                             if left_quote != ' ' {
233                                 if ch == left_quote {
234                                     left_quote = ' ';
235                                 }
236                                 stack.push(ch);
237                             } else {
238                                 //不存在未闭合的左引号
239                                 if ch == '\'' || ch == '\"' {
240                                     //字符为引号,记录下来
241                                     left_quote = ch;
242                                     stack.push(ch);
243                                 } else if ch == ' ' {
244                                     if !stack.is_empty() {
245                                         //字符为空格且栈中不为空,该空格视作命令段之间的分割线
246                                         //将栈中字符作为一个命令段加入集合,之后重置栈
247                                         fragments.push(stack.to_string());
248                                         stack.clear();
249                                     }
250                                 } else {
251                                     //其他字符都作为普通字符加入栈中
252                                     stack.push(ch);
253                                 }
254                             }
255                         }
256                         //结束时如果栈不为空
257                         if !stack.is_empty() {
258                             fragments.push(stack.to_string());
259                         } else {
260                             //结束时如果栈为空,说明光标左边的字符不属于任何命令片段,无法进行补全
261                             return 1;
262                         }
263 
264                         let mut target_fragment = fragments.last().unwrap().clone();
265                         target_fragment = target_fragment.replace("\'", "").replace("\"", "");
266 
267                         let (prefix, candidates) = if fragments.len() < 2 {
268                             //补全命令
269                             complete_command(&target_fragment)
270                         } else {
271                             //补全参数
272                             complete_path(&target_fragment)
273                         };
274 
275                         match candidates.len() {
276                             1 => {
277                                 let old_fragment = fragments.last().unwrap();
278                                 let candidate = candidates.last().unwrap();
279                                 self.printer.cursor -= old_fragment.len();
280                                 self.printer.flush_cursor();
281                                 self.printer.delete(old_fragment.len());
282                                 self.printer
283                                     .insert(format!("{}{}", prefix, candidate).as_bytes());
284                             }
285                             2.. => {
286                                 let old_cursor = self.printer.cursor;
287                                 self.printer.end();
288                                 println!();
289                                 for candidate in candidates {
290                                     print!(
291                                         "{}\t",
292                                         if candidate.ends_with('/') {
293                                             candidate.truecolor(0x00, 0x88, 0xff)
294                                         } else {
295                                             candidate.white()
296                                         }
297                                     );
298                                 }
299                                 println!();
300                                 self.printer.print_prompt();
301                                 Printer::print(&self.printer.buf.deref().borrow());
302                                 self.printer.cursor = old_cursor;
303                                 self.printer.flush_cursor();
304                             }
305                             _ => {}
306                         }
307                     }
308 
309                     _ => {}
310                 }
311             } else {
312                 match key {
313                     1..=31 => {}
314                     c => {
315                         self.printer.insert(&[c]);
316                     }
317                 }
318             }
319             stdout.flush().unwrap();
320         }
321     }
322 }
323 
324 struct Printer {
325     prompt: Prompt,
326     buf: Rc<RefCell<Vec<u8>>>,
327     cursor: usize,
328 }
329 
330 impl Printer {
331     fn new(bytes: &Rc<RefCell<Vec<u8>>>) -> Self {
332         let len = bytes.deref().borrow().len();
333         Printer {
334             prompt: Prompt {
335                 computer_name: "DragonOS".to_string(),
336                 user_name: "root".to_string(),
337                 path: std::env::current_dir()
338                     .expect("Error getting current directory")
339                     .to_str()
340                     .unwrap()
341                     .to_string(),
342             },
343             buf: Rc::clone(bytes),
344             cursor: len,
345         }
346     }
347 
348     fn init_before_readline(&mut self) {
349         self.buf = Rc::new(RefCell::new(Vec::new()));
350         self.prompt.update_path();
351         self.print_prompt();
352         self.cursor = 0;
353         self.flush_cursor();
354     }
355 
356     fn print_prompt(&self) {
357         print!("{}", self.prompt);
358         stdout().flush().unwrap();
359     }
360 
361     //在光标处插入字符串
362     fn insert(&mut self, bytes: &[u8]) {
363         let mut buf = self.buf.deref().borrow_mut();
364         // self.delete_to_cursor(buf.len() - cursor);
365         // print!("{}"," ".repeat(buf.len() - cursor));
366         Printer::print(bytes);
367         Printer::print(&buf[self.cursor..]);
368         buf.splice(self.cursor..self.cursor, bytes.iter().cloned());
369         self.cursor += bytes.len();
370         self.flush_cursor();
371         stdout().flush().unwrap();
372     }
373 
374     //删除下标为[cursor,cursor + len)的字符,光标位置不变
375     fn delete(&self, len: usize) {
376         let cursor = self.cursor;
377         let mut buf = self.buf.deref().borrow_mut();
378         if cursor + len - 1 < buf.len() {
379             Printer::print(&buf[cursor + len..]);
380             print!("{}", " ".repeat(len));
381             self.flush_cursor();
382             buf.drain(cursor..cursor + len);
383             stdout().flush().unwrap();
384         }
385     }
386 
387     fn backspace(&mut self) {
388         if self.cursor > 0 {
389             crossterm::execute!(io::stdout(), crossterm::cursor::MoveLeft(1)).unwrap();
390             self.cursor -= 1;
391             self.flush_cursor();
392             self.delete(1);
393         }
394     }
395 
396     fn flush_cursor(&self) {
397         crossterm::execute!(
398             io::stdout(),
399             crossterm::cursor::MoveToColumn((self.cursor + self.prompt.len()) as u16)
400         )
401         .unwrap();
402     }
403 
404     fn cursor_left(&mut self) {
405         if self.cursor > 0 {
406             crossterm::execute!(io::stdout(), crossterm::cursor::MoveLeft(1)).unwrap();
407             self.cursor -= 1;
408         }
409     }
410 
411     fn cursor_right(&mut self) {
412         let buf = self.buf.deref().borrow();
413         if self.cursor < buf.len() {
414             crossterm::execute!(io::stdout(), crossterm::cursor::MoveRight(1)).unwrap();
415             self.cursor += 1;
416         }
417     }
418 
419     fn home(&mut self) {
420         self.cursor = 0;
421         self.flush_cursor();
422     }
423 
424     fn end(&mut self) {
425         self.cursor = self.buf.deref().borrow().len();
426         self.flush_cursor();
427     }
428 
429     fn change_line(&mut self, new_buf: &Rc<RefCell<Vec<u8>>>) {
430         let old_buf_borrow = self.buf.deref().borrow();
431         let new_buf_borrow = new_buf.deref().borrow();
432         self.cursor = 0;
433         self.flush_cursor();
434         Printer::print(&new_buf_borrow[..]);
435         self.cursor = new_buf_borrow.len();
436         if new_buf_borrow.len() < old_buf_borrow.len() {
437             print!(
438                 "{}",
439                 " ".repeat(old_buf_borrow.len() - new_buf_borrow.len())
440             );
441             self.flush_cursor();
442         }
443         drop(old_buf_borrow);
444         drop(new_buf_borrow);
445         self.buf = Rc::clone(new_buf);
446         stdout().flush().unwrap();
447     }
448 
449     fn print(bytes: &[u8]) {
450         print!("{}", String::from_utf8(bytes.to_vec()).unwrap());
451     }
452 }
453 
454 // 测试终端颜色显示效果
455 #[allow(dead_code)]
456 pub fn _print_color_example() {
457     let example = "abcdefghijklmnopqrstuvwxyz";
458     println!("{}", example.bright_black());
459     println!("{}", example.bright_blue());
460     println!("{}", example.bright_cyan());
461     println!("{}", example.bright_green());
462     println!("{}", example.bright_magenta());
463     println!("{}", example.bright_purple());
464     println!("{}", example.bright_red());
465     println!("{}", example.bright_white());
466     println!("{}", example.bright_yellow());
467     println!("{}", example.black());
468     println!("{}", example.blue());
469     println!("{}", example.cyan());
470     println!("{}", example.green());
471     println!("{}", example.magenta());
472     println!("{}", example.purple());
473     println!("{}", example.red());
474     println!("{}", example.white());
475     println!("{}", example.yellow());
476 }
477 
478 pub fn complete_command(command: &str) -> (&str, Vec<String>) {
479     let mut candidates: Vec<String> = Vec::new();
480     for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD {
481         if cmd.starts_with(command) {
482             candidates.push(String::from(*cmd));
483         }
484     }
485     ("", candidates)
486 }
487 
488 pub fn complete_path(incomplete_path: &str) -> (&str, Vec<String>) {
489     let mut candidates: Vec<String> = Vec::new();
490     let mut dir = "";
491     let incomplete_name: &str;
492     if let Some(index) = incomplete_path.rfind('/') {
493         dir = &incomplete_path[..=index];
494         incomplete_name = &incomplete_path[index + 1..];
495     } else {
496         incomplete_name = incomplete_path;
497     }
498     if let Ok(read_dir) = fs::read_dir(if dir.is_empty() { "." } else { dir }) {
499         // if incomplete_name == "" {
500         //     for entry in read_dir {
501         //         let entry = entry.unwrap();
502         //         let mut file_name = entry.file_name().into_string().unwrap();
503         //         if entry.file_type().unwrap().is_dir() {
504         //             file_name.push('/');
505         //         }
506         //         candidates.push(file_name);
507         //     }
508         // } else {
509         for entry in read_dir {
510             let entry = entry.unwrap();
511             let mut file_name = entry.file_name().into_string().unwrap();
512             if file_name.starts_with(incomplete_name) {
513                 if file_name.contains(' ') {
514                     file_name = format!("\'{}\'", file_name);
515                 }
516                 if entry.file_type().unwrap().is_dir() {
517                     file_name.push('/');
518                 }
519                 candidates.push(file_name);
520             }
521         }
522         // }
523     }
524 
525     return (dir, candidates);
526 }
527