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.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 Printer::print(&[CR, LF]); 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(&[LF]).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 key[0] == 224 { 128 Self::read_char(&mut key[0]); 129 // stdin.read(&mut key).unwrap(); 130 if key[0] == b'\x1b' { 131 panic!(); 132 } 133 if key[0] == UP || key[0] == DOWN { 134 if key[0] == UP && command_index > 0 { 135 command_index -= 1; 136 } 137 if key[0] == DOWN && command_index < len { 138 command_index += 1; 139 } 140 let old_length = buf.len(); 141 buf = history_commands.get_mut(command_index).unwrap(); 142 Printer::replace(&buf, old_length); 143 cursor = buf.len() - 1; 144 } 145 146 if key[0] == LEFT || key[0] == RIGHT { 147 match key[0] { 148 LEFT => { 149 if cursor > 0 { 150 Printer::set_cursor(buf, cursor, cursor - 1); 151 cursor -= 1; 152 } 153 } 154 155 RIGHT => { 156 if cursor < buf.len() - 1 { 157 Printer::set_cursor(buf, cursor, cursor + 1); 158 cursor += 1; 159 } 160 } 161 162 _ => {} 163 } 164 } 165 } else { 166 if key[0] == TAB && buf.len() > 1 && buf[cursor - 1] != b' ' { 167 let command: String = String::from_utf8(buf[..cursor].to_vec()).unwrap(); 168 let mut command_frag = command.split_ascii_whitespace().collect::<Vec<_>>(); 169 let incomplete_frag = command_frag.pop().unwrap(); 170 let mut incomplete_len: usize = incomplete_frag.len(); 171 let candidates = match command_frag.len() { 172 0 => Printer::complete_command(incomplete_frag), 173 1.. => { 174 if let Some(index) = incomplete_frag.rfind('/') { 175 incomplete_len = incomplete_frag.len() - index - 1; 176 } else { 177 incomplete_len = incomplete_frag.len(); 178 } 179 Printer::complete_path(incomplete_frag) 180 } 181 _ => Vec::new(), 182 }; 183 match candidates.len() { 184 1 => { 185 let complete_part = candidates[0][incomplete_len..].as_bytes(); 186 187 Printer::delete_from_index(cursor, buf.len()); 188 189 // stdout.write_all(complete_part).unwrap(); 190 Printer::print(complete_part); 191 192 Printer::print_cursor(buf[cursor]); 193 Printer::print(&buf[cursor + 1..]); 194 195 buf.splice(cursor..cursor, complete_part.iter().cloned()); 196 cursor += candidates[0].len() - incomplete_len; 197 } 198 2.. => { 199 Printer::delete_from_index(cursor, buf.len()); 200 Printer::print(&buf[cursor..buf.len()]); 201 Printer::print(&[CR, LF]); 202 for candidate in candidates { 203 print!("{candidate} "); 204 } 205 Printer::print(&[CR, LF]); 206 Printer::print_prompt(&prompt); 207 Printer::print(&buf[..buf.len() - 1]); 208 Printer::print_cursor(b' '); 209 } 210 _ => {} 211 } 212 } 213 214 match key[0] { 215 CR | LF => { 216 if cursor > 0 { 217 Printer::set_cursor(buf, cursor, buf.len()); 218 Printer::print(&[CR, LF]); 219 let mut command = buf.clone(); 220 buf = history_commands.get_mut(len).unwrap(); 221 buf.clear(); 222 buf.append(&mut command); 223 224 return 1; 225 } 226 } 227 BS | DL => { 228 if cursor > 0 { 229 Printer::delete(cursor, 1, buf); 230 buf.remove(cursor - 1); 231 cursor -= 1; 232 } 233 } 234 1..=31 => {} 235 c => { 236 Printer::insert(cursor, &[c], buf); 237 buf.insert(cursor, c); 238 cursor += 1; 239 } 240 } 241 } 242 stdout.flush().unwrap(); 243 } 244 } 245 } 246 247 struct Printer; 248 249 impl Printer { 250 fn print_prompt(current_dir: &String) { 251 io::stdout().flush().unwrap(); 252 unsafe { 253 syscall(100000, "[DragonOS]:\0".as_ptr(), 0x0000ff90, 0x00000000); 254 255 syscall( 256 100000, 257 format!("{}\0", current_dir).as_ptr(), 258 0x000088ff, 259 0x00000000, 260 ); 261 print!("$ "); 262 } 263 } 264 265 fn print_cursor(c: u8) { 266 Self::print_color(&[c], 0x00000000, 0x00ffffff); 267 } 268 269 fn delete_from_index(index: usize, length: usize) { 270 for _i in 0..length - index { 271 Printer::print(&[BS, SPACE, BS]); 272 } 273 } 274 275 fn insert(cursor: usize, bytes: &[u8], buf: &Vec<u8>) { 276 Printer::delete_from_index(cursor, buf.len()); 277 Printer::print(bytes); 278 Printer::print_cursor(buf[cursor]); 279 Printer::print(&buf[cursor + 1..]); 280 } 281 282 fn delete(cursor: usize, length: usize, buf: &Vec<u8>) { 283 Printer::delete_from_index(cursor - length, buf.len()); 284 Printer::print_cursor(buf[cursor]); 285 Printer::print(&buf[cursor + 1..]); 286 } 287 288 fn replace(bytes: &[u8], old_length: usize) { 289 Printer::delete_from_index(0, old_length); 290 Printer::print(&bytes[0..bytes.len() - 1]); 291 Printer::print_cursor(b' '); 292 } 293 294 fn print(bytes: &[u8]) { 295 print!("{}", String::from_utf8(bytes.to_vec()).unwrap()); 296 } 297 298 fn print_color(bytes: &[u8], front_color: usize, background_color: usize) { 299 std::io::stdout().flush().unwrap(); 300 let cstr = std::ffi::CString::new(bytes).unwrap(); 301 unsafe { 302 dsc::syscall!(SYS_PUT_STRING, cstr.as_ptr(), front_color, background_color); 303 } 304 } 305 306 fn set_cursor(buf: &mut Vec<u8>, old_index: usize, new_index: usize) { 307 if new_index < buf.len() { 308 let index = std::cmp::min(old_index, new_index); 309 Printer::delete_from_index(index, buf.len()); 310 Printer::print(&buf[index..new_index]); 311 Printer::print_cursor(buf[new_index]); 312 Printer::print(&buf[new_index + 1..]); 313 } else { 314 Printer::delete_from_index(old_index, buf.len()); 315 Printer::print(&buf[old_index..]); 316 } 317 } 318 319 fn complete_command(command: &str) -> Vec<String> { 320 let mut candidates: Vec<String> = Vec::new(); 321 for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD { 322 if cmd.starts_with(command) { 323 candidates.push(String::from(*cmd)); 324 } 325 } 326 candidates 327 } 328 329 fn complete_path(path: &str) -> Vec<String> { 330 let mut candidates: Vec<String> = Vec::new(); 331 let dir: &str; 332 let incomplete_name: &str; 333 if let Some(index) = path.rfind('/') { 334 dir = &path[..=index]; 335 if index < path.len() { 336 incomplete_name = &path[index + 1..]; 337 } else { 338 incomplete_name = ""; 339 } 340 } else { 341 dir = "."; 342 incomplete_name = &path[..]; 343 } 344 match fs::read_dir(dir) { 345 Ok(read_dir) => { 346 if incomplete_name == "" { 347 for entry in read_dir { 348 let entry = entry.unwrap(); 349 let mut file_name = entry.file_name().into_string().unwrap(); 350 if entry.file_type().unwrap().is_dir() { 351 file_name.push('/'); 352 } 353 candidates.push(file_name); 354 } 355 } else { 356 for entry in read_dir { 357 let entry = entry.unwrap(); 358 let mut file_name = entry.file_name().into_string().unwrap(); 359 if file_name.starts_with(incomplete_name) { 360 if entry.file_type().unwrap().is_dir() { 361 file_name.push('/'); 362 } 363 candidates.push(file_name); 364 } 365 } 366 } 367 } 368 369 Err(_) => {} 370 } 371 return candidates; 372 } 373 } 374