1 use core::fmt; 2 use std::{ 3 cell::RefCell, 4 fs::{self, File, OpenOptions}, 5 io::{self, stdout, BufRead, BufReader, Read, Write}, 6 ops::Deref, 7 path::Path, 8 print, 9 rc::Rc, 10 string::String, 11 vec::Vec, 12 }; 13 14 use crate::keycode::{FunctionKeySuffix, SpecialKeycode}; 15 16 use colored::Colorize; 17 use command::{BuildInCmd, Command}; 18 19 pub mod command; 20 21 pub struct Prompt { 22 user_name: String, 23 computer_name: String, 24 path: String, 25 } 26 27 impl Prompt { 28 pub fn len(&self) -> usize { 29 format!("{}@{}:{}$ ", self.user_name, self.computer_name, self.path).len() 30 } 31 32 pub fn update_path(&mut self) { 33 self.path = std::env::current_dir() 34 .unwrap() 35 .to_str() 36 .unwrap() 37 .to_string(); 38 } 39 } 40 41 impl fmt::Display for Prompt { 42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 43 write!( 44 f, 45 "{}:{}$ ", 46 format!("{}@{}", self.user_name, self.computer_name).bright_green(), 47 self.path.bright_cyan() 48 ) 49 } 50 } 51 52 pub struct Shell { 53 history_commands: Vec<Rc<RefCell<Vec<u8>>>>, 54 history_path: String, 55 printer: Printer, 56 } 57 58 impl Shell { 59 pub fn new() -> Shell { 60 let mut shell = Shell { 61 history_commands: Vec::new(), 62 history_path: "history_commands.txt".to_string(), 63 printer: Printer::new(&Rc::new(RefCell::new(Vec::new()))), 64 }; 65 shell.read_commands(); 66 shell 67 } 68 69 pub fn current_dir() -> String { 70 std::env::current_dir() 71 .expect("Error getting current directory") 72 .to_str() 73 .unwrap() 74 .to_string() 75 } 76 77 pub fn chdir(&mut self, new_dir: &String) { 78 let path = Path::new(&new_dir); 79 if let Err(e) = std::env::set_current_dir(&path) { 80 eprintln!("Error changing directory: {}", e); 81 } 82 } 83 84 pub fn exec(&mut self) { 85 crossterm::terminal::enable_raw_mode().expect("failed to enable raw mode"); 86 loop { 87 self.printer.init_before_readline(); 88 if self.readline() == 0 { 89 println!(); 90 break; 91 } 92 let command_bytes = self.printer.buf.borrow().clone(); 93 if !command_bytes.starts_with(&[b' ']) 94 && command_bytes 95 != self 96 .history_commands 97 .last() 98 .unwrap_or(&Rc::new(RefCell::new(Vec::new()))) 99 .borrow() 100 .clone() 101 { 102 self.history_commands 103 .push(Rc::new(RefCell::new(command_bytes.clone()))); 104 }; 105 if !command_bytes.iter().all(|&byte| byte == b' ') { 106 self.exec_commands_in_line(&command_bytes); 107 } 108 } 109 self.write_commands(); 110 } 111 112 fn exec_commands_in_line(&mut self, command_bytes: &Vec<u8>) { 113 let commands = Command::from_strings(String::from_utf8(command_bytes.clone()).unwrap()); 114 commands 115 .iter() 116 .for_each(|command| self.exec_command(command)); 117 } 118 119 pub fn read_commands(&mut self) { 120 let mut history = Vec::new(); 121 for line in BufReader::new(match File::open(&self.history_path) { 122 Ok(file) => file, 123 Err(_) => File::create(&self.history_path).unwrap(), 124 }) 125 .lines() 126 { 127 match line { 128 Ok(s) => history.push(Rc::new(RefCell::new(s.into_bytes()))), 129 Err(_) => { 130 break; 131 } 132 } 133 } 134 self.history_commands = history; 135 } 136 137 fn write_commands(&self) { 138 let mut file = OpenOptions::new() 139 .append(false) 140 .open("history_commands.txt") 141 .unwrap(); 142 for command_line in &self.history_commands { 143 file.write_all(&command_line.borrow()[..]).unwrap(); 144 file.write_all(&[SpecialKeycode::LF.into()]).unwrap(); 145 } 146 } 147 148 fn read_char() -> u8 { 149 let mut buf: [u8; 1] = [0]; 150 std::io::stdin().read(&mut buf).expect("read char error"); 151 buf[0] 152 } 153 154 fn readline(&mut self) -> usize { 155 let mut stdout = std::io::stdout(); 156 self.history_commands.push(Rc::clone(&self.printer.buf)); 157 let mut command_index = self.history_commands.len() - 1; 158 loop { 159 let key = Self::read_char(); 160 if let Ok(special_key) = SpecialKeycode::try_from(key) { 161 match special_key { 162 SpecialKeycode::FunctionKeyPrefix => { 163 let key = Self::read_char(); 164 let function_key = FunctionKeySuffix::try_from(key).unwrap(); 165 match function_key { 166 FunctionKeySuffix::Up => { 167 if command_index > 0 { 168 command_index -= 1; 169 self.printer.change_line( 170 self.history_commands.get(command_index).unwrap(), 171 ); 172 } 173 } 174 175 FunctionKeySuffix::Down => { 176 if command_index < self.history_commands.len() - 1 { 177 command_index += 1; 178 self.printer.change_line( 179 self.history_commands.get(command_index).unwrap(), 180 ); 181 } 182 } 183 184 FunctionKeySuffix::Left => { 185 self.printer.cursor_left(); 186 } 187 188 FunctionKeySuffix::Right => { 189 self.printer.cursor_right(); 190 } 191 192 FunctionKeySuffix::Home => { 193 self.printer.home(); 194 } 195 196 FunctionKeySuffix::End => { 197 self.printer.end(); 198 } 199 } 200 } 201 202 SpecialKeycode::LF | SpecialKeycode::CR => { 203 println!(); 204 self.history_commands.pop(); 205 return 1; 206 } 207 208 SpecialKeycode::BackSpace => { 209 self.printer.backspace(); 210 } 211 212 SpecialKeycode::Delete => { 213 self.printer.delete(1); 214 } 215 216 SpecialKeycode::Tab => { 217 let mut buf = self.printer.buf.deref().borrow().clone(); 218 buf.truncate(self.printer.cursor); 219 let str = String::from_utf8(buf.clone()).unwrap(); 220 if buf.len() == 0 || buf.iter().all(|byte| *byte == b' ') { 221 return 1; 222 } 223 224 let iter = str.chars(); 225 let mut fragments: Vec<String> = Vec::new(); 226 let mut stack: String = String::with_capacity(str.len()); 227 let mut left_quote: char = ' '; 228 for ch in iter { 229 //存在未闭合的左引号,此时除能够配对的引号外,任何字符都加入栈中 230 if left_quote != ' ' { 231 if ch == left_quote { 232 left_quote = ' '; 233 } 234 stack.push(ch); 235 } else { 236 //不存在未闭合的左引号 237 if ch == '\'' || ch == '\"' { 238 //字符为引号,记录下来 239 left_quote = ch; 240 stack.push(ch); 241 } else if ch == ' ' { 242 if !stack.is_empty() { 243 //字符为空格且栈中不为空,该空格视作命令段之间的分割线 244 //将栈中字符作为一个命令段加入集合,之后重置栈 245 fragments.push(stack.to_string()); 246 stack.clear(); 247 } 248 } else { 249 //其他字符都作为普通字符加入栈中 250 stack.push(ch); 251 } 252 } 253 } 254 //结束时如果栈不为空 255 if !stack.is_empty() { 256 fragments.push(stack.to_string()); 257 } else { 258 //结束时如果栈为空,说明光标左边的字符不属于任何命令片段,无法进行补全 259 return 1; 260 } 261 262 let mut target_fragment = fragments.last().unwrap().clone(); 263 target_fragment = target_fragment.replace("\'", "").replace("\"", ""); 264 265 let candidates = if fragments.len() < 2 { 266 //补全命令 267 complete_command(&target_fragment) 268 } else { 269 //补全参数 270 complete_path(&target_fragment) 271 }; 272 273 match candidates.len() { 274 1 => { 275 let old_fragment = fragments.last().unwrap(); 276 let candidate = candidates.last().unwrap(); 277 self.printer.cursor -= old_fragment.len(); 278 self.printer.flush_cursor(); 279 self.printer.delete(old_fragment.len()); 280 self.printer.insert(candidate.as_bytes()); 281 } 282 2.. => { 283 let old_cursor = self.printer.cursor; 284 self.printer.end(); 285 println!(); 286 for candidate in candidates { 287 print!( 288 "{}\t", 289 if candidate.ends_with('/') { 290 candidate.truecolor(0x00, 0x88, 0xff) 291 } else { 292 candidate.white() 293 } 294 ); 295 } 296 println!(); 297 self.printer.print_prompt(); 298 Printer::print(&self.printer.buf.deref().borrow()); 299 self.printer.cursor = old_cursor; 300 self.printer.flush_cursor(); 301 } 302 _ => {} 303 } 304 } 305 306 _ => {} 307 } 308 } else { 309 match key { 310 1..=31 => {} 311 c => { 312 self.printer.insert(&[c]); 313 } 314 } 315 } 316 stdout.flush().unwrap(); 317 } 318 } 319 } 320 321 struct Printer { 322 prompt: Prompt, 323 buf: Rc<RefCell<Vec<u8>>>, 324 cursor: usize, 325 } 326 327 impl Printer { 328 fn new(bytes: &Rc<RefCell<Vec<u8>>>) -> Self { 329 let len = bytes.deref().borrow().len(); 330 Printer { 331 prompt: Prompt { 332 computer_name: "DragonOS".to_string(), 333 user_name: "root".to_string(), 334 path: std::env::current_dir() 335 .expect("Error getting current directory") 336 .to_str() 337 .unwrap() 338 .to_string(), 339 }, 340 buf: Rc::clone(bytes), 341 cursor: len, 342 } 343 } 344 345 fn init_before_readline(&mut self) { 346 self.buf = Rc::new(RefCell::new(Vec::new())); 347 self.prompt.update_path(); 348 self.print_prompt(); 349 self.cursor = 0; 350 self.flush_cursor(); 351 } 352 353 fn print_prompt(&self) { 354 print!("{}", self.prompt); 355 stdout().flush().unwrap(); 356 } 357 358 //在光标处插入字符串 359 fn insert(&mut self, bytes: &[u8]) { 360 let mut buf = self.buf.deref().borrow_mut(); 361 // self.delete_to_cursor(buf.len() - cursor); 362 // print!("{}"," ".repeat(buf.len() - cursor)); 363 Printer::print(bytes); 364 Printer::print(&buf[self.cursor..]); 365 buf.splice(self.cursor..self.cursor, bytes.iter().cloned()); 366 self.cursor += bytes.len(); 367 self.flush_cursor(); 368 stdout().flush().unwrap(); 369 } 370 371 //删除下标为[cursor,cursor + len)的字符,光标位置不变 372 fn delete(&self, len: usize) { 373 let cursor = self.cursor; 374 let mut buf = self.buf.deref().borrow_mut(); 375 if cursor + len - 1 < buf.len() { 376 Printer::print(&buf[cursor + len..]); 377 print!("{}", " ".repeat(len)); 378 self.flush_cursor(); 379 buf.drain(cursor..cursor + len); 380 stdout().flush().unwrap(); 381 } 382 } 383 384 fn backspace(&mut self) { 385 if self.cursor > 0 { 386 crossterm::execute!(io::stdout(), crossterm::cursor::MoveLeft(1)).unwrap(); 387 self.cursor -= 1; 388 self.flush_cursor(); 389 self.delete(1); 390 } 391 } 392 393 fn flush_cursor(&self) { 394 crossterm::execute!( 395 io::stdout(), 396 crossterm::cursor::MoveToColumn((self.cursor + self.prompt.len()) as u16) 397 ) 398 .unwrap(); 399 } 400 401 fn cursor_left(&mut self) { 402 if self.cursor > 0 { 403 crossterm::execute!(io::stdout(), crossterm::cursor::MoveLeft(1)).unwrap(); 404 self.cursor -= 1; 405 } 406 } 407 408 fn cursor_right(&mut self) { 409 let buf = self.buf.deref().borrow(); 410 if self.cursor < buf.len() { 411 crossterm::execute!(io::stdout(), crossterm::cursor::MoveRight(1)).unwrap(); 412 self.cursor += 1; 413 } 414 } 415 416 fn home(&mut self) { 417 self.cursor = 0; 418 self.flush_cursor(); 419 } 420 421 fn end(&mut self) { 422 self.cursor = self.buf.deref().borrow().len(); 423 self.flush_cursor(); 424 } 425 426 fn change_line(&mut self, new_buf: &Rc<RefCell<Vec<u8>>>) { 427 let old_buf_borrow = self.buf.deref().borrow(); 428 let new_buf_borrow = new_buf.deref().borrow(); 429 self.cursor = 0; 430 self.flush_cursor(); 431 Printer::print(&new_buf_borrow[..]); 432 self.cursor = new_buf_borrow.len(); 433 if new_buf_borrow.len() < old_buf_borrow.len() { 434 print!( 435 "{}", 436 " ".repeat(old_buf_borrow.len() - new_buf_borrow.len()) 437 ); 438 self.flush_cursor(); 439 } 440 drop(old_buf_borrow); 441 drop(new_buf_borrow); 442 self.buf = Rc::clone(new_buf); 443 stdout().flush().unwrap(); 444 } 445 446 fn print(bytes: &[u8]) { 447 print!("{}", String::from_utf8(bytes.to_vec()).unwrap()); 448 } 449 } 450 451 pub fn _print_color_example() { 452 let example = "abcdefghijklmnopqrstuvwxyz"; 453 println!("{}", example.bright_black()); 454 println!("{}", example.bright_blue()); 455 println!("{}", example.bright_cyan()); 456 println!("{}", example.bright_green()); 457 println!("{}", example.bright_magenta()); 458 println!("{}", example.bright_purple()); 459 println!("{}", example.bright_red()); 460 println!("{}", example.bright_white()); 461 println!("{}", example.bright_yellow()); 462 println!("{}", example.black()); 463 println!("{}", example.blue()); 464 println!("{}", example.cyan()); 465 println!("{}", example.green()); 466 println!("{}", example.magenta()); 467 println!("{}", example.purple()); 468 println!("{}", example.red()); 469 println!("{}", example.white()); 470 println!("{}", example.yellow()); 471 } 472 473 pub fn complete_command(command: &str) -> Vec<String> { 474 let mut candidates: Vec<String> = Vec::new(); 475 for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD { 476 if cmd.starts_with(command) { 477 candidates.push(String::from(*cmd)); 478 } 479 } 480 candidates 481 } 482 483 pub fn complete_path(incomplete_path: &str) -> Vec<String> { 484 let current_dir = std::env::current_dir().unwrap(); 485 let current_dir = current_dir.to_str().unwrap(); 486 let path = if incomplete_path.starts_with('/') { 487 String::from(incomplete_path) 488 } else { 489 format!("{}/{}", current_dir, incomplete_path) 490 }; 491 492 let mut candidates: Vec<String> = Vec::new(); 493 let dir: &str; 494 let incomplete_name: &str; 495 if let Some(index) = path.rfind('/') { 496 dir = &path[..=index]; 497 if index < path.len() { 498 incomplete_name = &path[index + 1..]; 499 } else { 500 incomplete_name = ""; 501 } 502 } else { 503 dir = "."; 504 incomplete_name = &path[..]; 505 } 506 match fs::read_dir(dir) { 507 Ok(read_dir) => { 508 if incomplete_name == "" { 509 for entry in read_dir { 510 let entry = entry.unwrap(); 511 let mut file_name = entry.file_name().into_string().unwrap(); 512 if entry.file_type().unwrap().is_dir() { 513 file_name.push('/'); 514 } 515 candidates.push(file_name); 516 } 517 } else { 518 for entry in read_dir { 519 let entry = entry.unwrap(); 520 let mut file_name = entry.file_name().into_string().unwrap(); 521 if file_name.starts_with(incomplete_name) { 522 if entry.file_type().unwrap().is_dir() { 523 file_name.push('/'); 524 } 525 candidates.push(file_name); 526 } 527 } 528 } 529 } 530 531 Err(_) => {} 532 } 533 return candidates; 534 } 535