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