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