xref: /NovaShell/src/shell/mod.rs (revision 001f2a751fdbbe2ca1054f72891585ac8ce77932)
1 use std::{
2     fs::{self, File, OpenOptions},
3     io::{self, BufRead, BufReader, Write},
4     path::Path,
5     print,
6     string::String,
7     vec::Vec,
8 };
9 
10 use crate::keycode::{FunctionKeySuffix, SpecialKeycode};
11 
12 use command::{BuildInCmd, Command};
13 
14 pub mod command;
15 
16 pub struct Shell {
17     history_commands: Vec<Vec<u8>>,
18     executed_commands: Vec<Vec<u8>>,
19 }
20 
21 impl Shell {
22     pub fn new() -> Shell {
23         let mut shell = Shell {
24             history_commands: Vec::new(),
25             executed_commands: Vec::new(),
26         };
27         shell.read_commands();
28         shell
29     }
30 
31     pub fn current_dir() -> String {
32         std::env::current_dir()
33             .expect("Error getting current directory")
34             .to_str()
35             .unwrap()
36             .to_string()
37     }
38 
39     pub fn chdir(&mut self, new_dir: &String) {
40         let path = Path::new(&new_dir);
41         if let Err(e) = std::env::set_current_dir(&path) {
42             eprintln!("Error changing directory: {}", e);
43         }
44     }
45 
46     pub fn exec(&mut self) {
47         let mut buf: Vec<u8>;
48         loop {
49             buf = Vec::new();
50             buf.push(b' ');
51             self.history_commands.push(buf);
52             Printer::print_prompt(&Self::current_dir());
53             if self.readline(0) == 0 {
54                 println!();
55                 break;
56             }
57             let command_bytes = self.history_commands.last().unwrap().clone();
58             if command_bytes.starts_with(&[b' ']) {
59                 self.history_commands.pop().unwrap();
60             } else {
61                 self.executed_commands.push(command_bytes.clone());
62             }
63             if !command_bytes.iter().all(|&byte| byte == b' ') {
64                 self.exec_command_in_bytes(&command_bytes);
65             }
66         }
67         self.write_commands();
68     }
69 
70     fn exec_command_in_bytes(&mut self, command_bytes: &Vec<u8>) {
71         let commands = Command::from_strings(String::from_utf8(command_bytes.clone()).unwrap());
72         commands
73             .iter()
74             .for_each(|command| self.exec_command(command));
75     }
76 
77     fn read_commands(&mut self) {
78         for line in BufReader::new(match File::open("history_commands.txt") {
79             Ok(file) => file,
80             Err(_) => File::create("history_commands.txt").unwrap(),
81         })
82         .lines()
83         {
84             match line {
85                 Ok(s) => self.history_commands.push(s.into_bytes()),
86                 Err(_) => {
87                     break;
88                 }
89             }
90         }
91     }
92 
93     fn write_commands(&self) {
94         let mut file = OpenOptions::new()
95             .append(true)
96             .open("history_commands.txt")
97             .unwrap();
98         for command_line in &self.executed_commands {
99             file.write_all(&command_line[..]).unwrap();
100             file.write_all(&[SpecialKeycode::LF.into()]).unwrap();
101         }
102     }
103 
104     fn read_char(byte: &mut u8) {
105         let mut c: libc::c_uchar = 0;
106         unsafe {
107             let p = &mut c as *mut libc::c_uchar as *mut libc::c_void;
108             libc::read(0, p, 1);
109         }
110         *byte = c;
111     }
112 
113     fn readline(&mut self, _fd: usize) -> usize {
114         let mut stdout = std::io::stdout();
115         let prompt: String = Self::current_dir().clone();
116         let len = self.history_commands.len() - 1;
117         let mut key: [u8; 1] = [0];
118         let mut command_index = len;
119         let mut buf = self.history_commands.get_mut(command_index).unwrap();
120         let mut cursor = 0;
121 
122         Printer::print_cursor(b' ');
123         stdout.flush().unwrap();
124         loop {
125             Self::read_char(&mut key[0]);
126             // if stdin.read(&mut key).ok() != Some(1) {
127             //     continue;
128             // }
129             if let Ok(special_key) = SpecialKeycode::try_from(key[0]) {
130                 match special_key {
131                     SpecialKeycode::FunctionKeyPrefix => {
132                         Self::read_char(&mut key[0]);
133                         let function_key = FunctionKeySuffix::try_from(key[0]).unwrap();
134                         match function_key {
135                             FunctionKeySuffix::Up => {
136                                 if command_index > 0 {
137                                     command_index -= 1;
138                                 }
139                                 let old_length = buf.len();
140                                 buf = self.history_commands.get_mut(command_index).unwrap();
141                                 Printer::replace(&buf, old_length);
142                                 cursor = buf.len() - 1;
143                             }
144 
145                             FunctionKeySuffix::Down => {
146                                 if command_index < len {
147                                     command_index += 1;
148                                 }
149                                 let old_length = buf.len();
150                                 buf = self.history_commands.get_mut(command_index).unwrap();
151                                 Printer::replace(&buf, old_length);
152                                 cursor = buf.len() - 1;
153                             }
154 
155                             FunctionKeySuffix::Left => {
156                                 if cursor > 0 {
157                                     Printer::set_cursor(buf, cursor, cursor - 1);
158                                     cursor -= 1;
159                                 }
160                             }
161 
162                             FunctionKeySuffix::Right => {
163                                 if cursor < buf.len() - 1 {
164                                     Printer::set_cursor(buf, cursor, cursor + 1);
165                                     cursor += 1;
166                                 }
167                             }
168 
169                             FunctionKeySuffix::Home => {
170                                 Printer::set_cursor(buf, cursor, 0);
171                             }
172 
173                             FunctionKeySuffix::End => {
174                                 Printer::set_cursor(buf, cursor, buf.len());
175                             }
176                         }
177                     }
178 
179                     SpecialKeycode::LF | SpecialKeycode::CR => {
180                         // println!("buf:{:?}\tcursor:{}\tbuf.len():{}", buf, cursor, buf.len());
181                         Printer::set_cursor(buf, cursor, buf.len());
182                         println!();
183                         let mut command = buf.clone();
184                         buf = self.history_commands.get_mut(len).unwrap();
185                         buf.clear();
186                         buf.append(&mut command);
187 
188                         return 1;
189                     }
190 
191                     SpecialKeycode::BackSpace => {
192                         if cursor > 0 {
193                             Printer::delete_to_cursor(cursor, 1, buf);
194                             buf.remove(cursor - 1);
195                             cursor -= 1;
196                         }
197                     }
198 
199                     SpecialKeycode::Delete => {
200                         if cursor < buf.len() - 1 {
201                             Printer::delete(cursor, buf);
202                             buf.remove(cursor);
203                         }
204                     }
205 
206                     SpecialKeycode::Tab => {
207                         if buf.len() > 1 && buf[cursor - 1] != b' ' {
208                             let command: String =
209                                 String::from_utf8(buf[..cursor].to_vec()).unwrap();
210                             let mut command_frag =
211                                 command.split_ascii_whitespace().collect::<Vec<_>>();
212                             let incomplete_frag = command_frag.pop().unwrap();
213                             let mut incomplete_len: usize = incomplete_frag.len();
214                             let candidates = match command_frag.len() {
215                                 0 => Printer::complete_command(incomplete_frag),
216                                 1.. => {
217                                     if let Some(index) = incomplete_frag.rfind('/') {
218                                         incomplete_len = incomplete_frag.len() - index - 1;
219                                     } else {
220                                         incomplete_len = incomplete_frag.len();
221                                     }
222                                     Printer::complete_path(
223                                         Self::current_dir().as_str(),
224                                         incomplete_frag,
225                                     )
226                                 }
227                                 _ => Vec::new(),
228                             };
229                             match candidates.len() {
230                                 1 => {
231                                     let complete_part = candidates[0][incomplete_len..].as_bytes();
232 
233                                     Printer::delete_from_index(cursor, buf.len());
234 
235                                     // stdout.write_all(complete_part).unwrap();
236                                     Printer::print(complete_part);
237 
238                                     Printer::print_cursor(buf[cursor]);
239                                     Printer::print(&buf[cursor + 1..]);
240 
241                                     buf.splice(cursor..cursor, complete_part.iter().cloned());
242                                     cursor += candidates[0].len() - incomplete_len;
243                                 }
244                                 2.. => {
245                                     Printer::delete_from_index(cursor, buf.len());
246                                     Printer::print(&buf[cursor..buf.len()]);
247                                     println!();
248                                     for candidate in candidates {
249                                         if candidate.ends_with('/') {
250                                             crate::shell::Printer::print_color(
251                                                 candidate.as_bytes(),
252                                                 0x000088ff,
253                                                 0x00000000,
254                                             );
255                                             print!("    ");
256                                         } else {
257                                             print!("{candidate}    ");
258                                         }
259                                     }
260                                     println!();
261                                     Printer::print_prompt(&prompt);
262                                     Printer::print(&buf[..buf.len() - 1]);
263                                     Printer::print_cursor(b' ');
264                                     Printer::set_cursor(buf, buf.len(), cursor);
265                                 }
266                                 _ => {}
267                             }
268                         }
269                     }
270 
271                     _ => {}
272                 }
273             } else {
274                 match key[0] {
275                     1..=31 => {}
276                     c => {
277                         Printer::insert(cursor, &[c], buf);
278                         buf.insert(cursor, c);
279                         cursor += 1;
280                     }
281                 }
282             }
283             stdout.flush().unwrap();
284         }
285     }
286 }
287 
288 struct Printer;
289 
290 impl Printer {
291     fn print_prompt(current_dir: &String) {
292         io::stdout().flush().unwrap();
293         Self::print_color("[DragonOS]:".as_bytes(), 0x0000ff90, 0x00000000);
294         Self::print_color(current_dir.as_bytes(), 0x000088ff, 0x00000000);
295         print!("$ ");
296     }
297 
298     fn print_cursor(c: u8) {
299         Self::print_color(&[c], 0x00000000, 0x00ffffff);
300     }
301 
302     fn delete_from_index(index: usize, length: usize) {
303         for _i in 0..length - index {
304             Printer::print(&[
305                 SpecialKeycode::BackSpace.into(),
306                 b' ',
307                 SpecialKeycode::BackSpace.into(),
308             ]);
309         }
310     }
311 
312     fn insert(cursor: usize, bytes: &[u8], buf: &Vec<u8>) {
313         Printer::delete_from_index(cursor, buf.len());
314         Printer::print(bytes);
315         Printer::print_cursor(buf[cursor]);
316         Printer::print(&buf[cursor + 1..]);
317     }
318 
319     fn delete(cursor: usize, buf: &Vec<u8>) {
320         if cursor < buf.len() - 1 {
321             Printer::delete_from_index(cursor, buf.len());
322             Printer::print_cursor(buf[cursor + 1]);
323             Printer::print(&buf[cursor + 2..]);
324         }
325     }
326 
327     fn delete_to_cursor(cursor: usize, length: usize, buf: &Vec<u8>) {
328         if cursor > 0 {
329             Printer::delete_from_index(cursor - length, buf.len());
330             Printer::print_cursor(buf[cursor]);
331             Printer::print(&buf[cursor + 1..]);
332         }
333     }
334 
335     fn replace(bytes: &[u8], old_length: usize) {
336         Printer::delete_from_index(0, old_length);
337         Printer::print(&bytes[0..bytes.len() - 1]);
338         Printer::print_cursor(b' ');
339     }
340 
341     fn print(bytes: &[u8]) {
342         print!("{}", String::from_utf8(bytes.to_vec()).unwrap());
343     }
344 
345     fn print_color(bytes: &[u8], front_color: usize, background_color: usize) {
346         std::io::stdout().flush().unwrap();
347         let cstr = std::ffi::CString::new(bytes).unwrap();
348         unsafe {
349             dsc::syscall!(SYS_PUT_STRING, cstr.as_ptr(), front_color, background_color);
350         }
351     }
352 
353     fn set_cursor(buf: &mut Vec<u8>, old_index: usize, new_index: usize) {
354         if new_index < buf.len() {
355             let index = std::cmp::min(old_index, new_index);
356             Printer::delete_from_index(index, buf.len());
357             Printer::print(&buf[index..new_index]);
358             Printer::print_cursor(buf[new_index]);
359             Printer::print(&buf[new_index + 1..]);
360         } else {
361             Printer::delete_from_index(old_index, buf.len());
362             Printer::print(&buf[old_index..]);
363         }
364     }
365 
366     fn complete_command(command: &str) -> Vec<String> {
367         let mut candidates: Vec<String> = Vec::new();
368         for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD {
369             if cmd.starts_with(command) {
370                 candidates.push(String::from(*cmd));
371             }
372         }
373         candidates
374     }
375 
376     fn complete_path(current_dir: &str, incomplete_path: &str) -> Vec<String> {
377         let path = if incomplete_path.starts_with('/') {
378             String::from(incomplete_path)
379         } else {
380             format!("{}/{}", current_dir, incomplete_path)
381         };
382 
383         let mut candidates: Vec<String> = Vec::new();
384         let dir: &str;
385         let incomplete_name: &str;
386         if let Some(index) = path.rfind('/') {
387             dir = &path[..=index];
388             if index < path.len() {
389                 incomplete_name = &path[index + 1..];
390             } else {
391                 incomplete_name = "";
392             }
393         } else {
394             dir = ".";
395             incomplete_name = &path[..];
396         }
397         match fs::read_dir(dir) {
398             Ok(read_dir) => {
399                 if incomplete_name == "" {
400                     for entry in read_dir {
401                         let entry = entry.unwrap();
402                         let mut file_name = entry.file_name().into_string().unwrap();
403                         if entry.file_type().unwrap().is_dir() {
404                             file_name.push('/');
405                         }
406                         candidates.push(file_name);
407                     }
408                 } else {
409                     for entry in read_dir {
410                         let entry = entry.unwrap();
411                         let mut file_name = entry.file_name().into_string().unwrap();
412                         if file_name.starts_with(incomplete_name) {
413                             if entry.file_type().unwrap().is_dir() {
414                                 file_name.push('/');
415                             }
416                             candidates.push(file_name);
417                         }
418                     }
419                 }
420             }
421 
422             Err(_) => {}
423         }
424         return candidates;
425     }
426 }
427