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