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