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