xref: /NovaShell/src/shell/mod.rs (revision 6f50094a7e1f5a323ffdd8ef4be4c22bba777501)
1 use libc::syscall;
2 use std::{
3     fs::{self, File, OpenOptions},
4     io::{self, BufRead, BufReader, Read, Write},
5     print,
6     string::String,
7     vec::Vec,
8 };
9 
10 use crate::{special_keycode::*, Env};
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     current_dir: String,
20 }
21 
22 impl Shell {
23     pub fn new() -> Shell {
24         let mut shell = Shell {
25             history_commands: Vec::new(),
26             executed_commands: Vec::new(),
27             current_dir: String::from("/"),
28         };
29         shell.read_commands();
30         shell
31     }
32 
33     pub fn current_dir(&self) -> String {
34         self.current_dir.clone()
35     }
36 
37     pub fn set_current_dir(&mut self, new_dir: String) {
38         self.current_dir = new_dir;
39         Env::insert(String::from("PWD"), self.current_dir());
40     }
41 
42     pub fn exec(&mut self) {
43         let mut buf: Vec<u8>;
44         loop {
45             buf = Vec::new();
46             buf.push(b' ');
47             self.history_commands.push(buf);
48             Printer::print_prompt(&self.current_dir);
49             if self.readline(0) == 0 {
50                 Printer::print(&[CR, LF]);
51                 break;
52             }
53             let command_bytes = self.history_commands.last().unwrap().clone();
54             self.exec_command_in_bytes(&command_bytes);
55         }
56         self.write_commands();
57     }
58 
59     fn exec_command_in_bytes(&mut self, command_bytes: &Vec<u8>) {
60         let commands = Command::from_strings(String::from_utf8(command_bytes.clone()).unwrap());
61         commands
62             .iter()
63             .for_each(|command| self.exec_command(command));
64     }
65 
66     fn read_commands(&mut self) {
67         for line in BufReader::new(match File::open("history_commands.txt") {
68             Ok(file) => file,
69             Err(_) => File::create("history_commands.txt").unwrap(),
70         })
71         .lines()
72         {
73             match line {
74                 Ok(s) => self.history_commands.push(s.into_bytes()),
75                 Err(_) => {
76                     break;
77                 }
78             }
79         }
80     }
81 
82     fn write_commands(&self) {
83         let mut file = OpenOptions::new()
84             .append(true)
85             .open("history_commands.txt")
86             .unwrap();
87         for command_line in &self.executed_commands {
88             file.write_all(&command_line[..]).unwrap();
89             file.write_all(&[LF]).unwrap();
90         }
91     }
92 
93     fn readline(&mut self, fd: usize) -> usize {
94         let mut stdin = std::io::stdin();
95         let mut stdout = std::io::stdout();
96         let prompt: String = self.current_dir.clone();
97         let history_commands = &mut self.history_commands;
98         let len = history_commands.len() - 1;
99         let mut key: [u8; 1] = [0];
100         let mut command_index = len;
101         let mut buf = history_commands.get_mut(command_index).unwrap();
102         let mut cursor = 0;
103 
104         Printer::print_cursor(b' ');
105         stdout.flush().unwrap();
106         loop {
107             let mut c: libc::c_uchar = 0;
108             unsafe {
109                 let p = &mut c as *mut libc::c_uchar as *mut libc::c_void;
110                 libc::read(0, p, 1);
111                 key[0] = c;
112             }
113             // if stdin.read(&mut key).ok() != Some(1) {
114             //     continue;
115             // }
116             if key[0] == 224 {
117                 stdin.read(&mut key).unwrap();
118                 if key[0] == b'\x1b' {
119                     panic!();
120                 }
121                 if key[0] == UP || key[0] == DOWN {
122                     Printer::delete_from_index(0, buf.len());
123 
124                     match key[0] {
125                         UP => {
126                             if command_index > 0 {
127                                 command_index -= 1;
128                             }
129                         }
130 
131                         DOWN => {
132                             if command_index < len {
133                                 command_index += 1;
134                             }
135                         }
136 
137                         _ => {}
138                     }
139                     buf = history_commands.get_mut(command_index).unwrap();
140                     Printer::print(&buf[..buf.len() - 1]);
141                     cursor = buf.len() - 1;
142                     Printer::print_cursor(b' ');
143                 }
144 
145                 if key[0] == LEFT || key[0] == RIGHT {
146                     match key[0] {
147                         LEFT => {
148                             if cursor > 0 {
149                                 Printer::set_cursor(buf, cursor, cursor - 1);
150                                 cursor -= 1;
151                             }
152                         }
153 
154                         RIGHT => {
155                             if cursor < buf.len() - 1 {
156                                 Printer::set_cursor(buf, cursor, cursor + 1);
157                                 cursor += 1;
158                             }
159                         }
160 
161                         _ => {}
162                     }
163                 }
164             } else {
165                 if key[0] == TAB && buf.len() > 1 && buf[cursor - 1] != b' ' {
166                     let command: String = String::from_utf8(buf[..cursor].to_vec()).unwrap();
167                     let mut command_frag = command.split_ascii_whitespace().collect::<Vec<_>>();
168                     let incomplete_frag = command_frag.pop().unwrap();
169                     let mut incomplete_len: usize = incomplete_frag.len();
170                     let candidates = match command_frag.len() {
171                         0 => Printer::complete_command(incomplete_frag),
172                         1.. => {
173                             if let Some(index) = incomplete_frag.rfind('/') {
174                                 incomplete_len = incomplete_frag.len() - index - 1;
175                             } else {
176                                 incomplete_len = incomplete_frag.len();
177                             }
178                             Printer::complete_path(incomplete_frag)
179                         }
180                         _ => Vec::new(),
181                     };
182                     match candidates.len() {
183                         1 => {
184                             let complete_part = candidates[0][incomplete_len..].as_bytes();
185 
186                             Printer::delete_from_index(cursor, buf.len());
187 
188                             // stdout.write_all(complete_part).unwrap();
189                             Printer::print(complete_part);
190 
191                             Printer::print_cursor(buf[cursor]);
192                             Printer::print(&buf[cursor + 1..]);
193 
194                             buf.splice(cursor..cursor, complete_part.iter().cloned());
195                             cursor += candidates[0].len() - incomplete_len;
196                         }
197                         2.. => {
198                             Printer::delete_from_index(cursor, buf.len());
199                             Printer::print(&buf[cursor..buf.len()]);
200                             Printer::print(&[CR, LF]);
201                             for candidate in candidates {
202                                 print!("{candidate}    ");
203                             }
204                             Printer::print(&[CR, LF]);
205                             Printer::print_prompt(&prompt);
206                             Printer::print(&buf[..buf.len() - 1]);
207                             Printer::print_cursor(b' ');
208                         }
209                         _ => {}
210                     }
211                 }
212 
213                 match key[0] {
214                     CR | LF => {
215                         if cursor > 0 {
216                             Printer::set_cursor(buf, cursor, buf.len());
217                             Printer::print(&[CR, LF]);
218                             let mut command = buf.clone();
219                             buf = history_commands.get_mut(len).unwrap();
220                             buf.clear();
221                             buf.append(&mut command);
222 
223                             return 1;
224                         }
225                     }
226                     BS | DL => {
227                         if cursor > 0 {
228                             Printer::delete_from_index(cursor, buf.len());
229                             cursor -= 1;
230                             buf.remove(cursor);
231                             // stdout.write_all(&[BS]).unwrap();
232                             Printer::print(&[BS]);
233                             Printer::print_cursor(buf[cursor]);
234                             Printer::print(&buf[cursor + 1..]);
235                         }
236                     }
237                     1..=31 => {}
238                     c => {
239                         Printer::delete_from_index(cursor, buf.len());
240                         Printer::print(&[c]);
241                         buf.insert(cursor, c);
242                         cursor += 1;
243                         Printer::print_cursor(buf[cursor]);
244                         Printer::print(&buf[cursor + 1..]);
245                     }
246                 }
247             }
248             stdout.flush().unwrap();
249         }
250     }
251 }
252 
253 struct Printer;
254 
255 impl Printer {
256     fn print_prompt(current_dir: &String) {
257         io::stdout().flush().unwrap();
258         unsafe {
259             syscall(100000, "[DragonOS]:\0".as_ptr(), 0x0000ff90, 0x00000000);
260 
261             syscall(
262                 100000,
263                 format!("{}\0", current_dir).as_ptr(),
264                 0x000088ff,
265                 0x00000000,
266             );
267             print!("$ ");
268         }
269     }
270 
271     fn print_cursor(c: u8) {
272         Self::print_color(&[c], 0x00000000, 0x00ffffff);
273     }
274 
275     fn delete_from_index(index: usize, length: usize) {
276         for _i in 0..length - index {
277             Printer::print(&[BS, SPACE, BS]);
278         }
279     }
280 
281     fn print(bytes: &[u8]) {
282         print!("{}", String::from_utf8(bytes.to_vec()).unwrap());
283     }
284 
285     fn print_color(bytes: &[u8], front_color: usize, background_color: usize) {
286         std::io::stdout().flush().unwrap();
287         let cstr = std::ffi::CString::new(bytes).unwrap();
288         unsafe {
289             dsc::syscall!(SYS_PUT_STRING, cstr.as_ptr(), front_color, background_color);
290         }
291     }
292 
293     fn set_cursor(buf: &mut Vec<u8>, old_index: usize, new_index: usize) {
294         if new_index < buf.len() {
295             let index = std::cmp::min(old_index, new_index);
296             Printer::delete_from_index(index, buf.len());
297             Printer::print(&buf[index..new_index]);
298             Printer::print_cursor(buf[new_index]);
299             Printer::print(&buf[new_index + 1..]);
300         } else {
301             Printer::delete_from_index(old_index, buf.len());
302             Printer::print(&buf[old_index..]);
303         }
304     }
305 
306     fn complete_command(command: &str) -> Vec<String> {
307         let mut candidates: Vec<String> = Vec::new();
308         for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD {
309             if cmd.starts_with(command) {
310                 candidates.push(String::from(*cmd));
311             }
312         }
313         candidates
314     }
315 
316     fn complete_path(path: &str) -> Vec<String> {
317         let mut candidates: Vec<String> = Vec::new();
318         let dir: &str;
319         let incomplete_name: &str;
320         if let Some(index) = path.rfind('/') {
321             dir = &path[..=index];
322             if index < path.len() {
323                 incomplete_name = &path[index + 1..];
324             } else {
325                 incomplete_name = "";
326             }
327         } else {
328             dir = ".";
329             incomplete_name = &path[..];
330         }
331         match fs::read_dir(dir) {
332             Ok(read_dir) => {
333                 if incomplete_name == "" {
334                     for entry in read_dir {
335                         let entry = entry.unwrap();
336                         let mut file_name = entry.file_name().into_string().unwrap();
337                         if entry.file_type().unwrap().is_dir() {
338                             file_name.push('/');
339                         }
340                         candidates.push(file_name);
341                     }
342                 } else {
343                     for entry in read_dir {
344                         let entry = entry.unwrap();
345                         let mut file_name = entry.file_name().into_string().unwrap();
346                         if file_name.starts_with(incomplete_name) {
347                             if entry.file_type().unwrap().is_dir() {
348                                 file_name.push('/');
349                             }
350                             candidates.push(file_name);
351                         }
352                     }
353                 }
354             }
355 
356             Err(_) => {}
357         }
358         return candidates;
359     }
360 }
361