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 (prefix, 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 281 .insert(format!("{}{}", prefix, candidate).as_bytes()); 282 } 283 2.. => { 284 let old_cursor = self.printer.cursor; 285 self.printer.end(); 286 println!(); 287 for candidate in candidates { 288 print!( 289 "{}\t", 290 if candidate.ends_with('/') { 291 candidate.truecolor(0x00, 0x88, 0xff) 292 } else { 293 candidate.white() 294 } 295 ); 296 } 297 println!(); 298 self.printer.print_prompt(); 299 Printer::print(&self.printer.buf.deref().borrow()); 300 self.printer.cursor = old_cursor; 301 self.printer.flush_cursor(); 302 } 303 _ => {} 304 } 305 } 306 307 _ => {} 308 } 309 } else { 310 match key { 311 1..=31 => {} 312 c => { 313 self.printer.insert(&[c]); 314 } 315 } 316 } 317 stdout.flush().unwrap(); 318 } 319 } 320 } 321 322 struct Printer { 323 prompt: Prompt, 324 buf: Rc<RefCell<Vec<u8>>>, 325 cursor: usize, 326 } 327 328 impl Printer { 329 fn new(bytes: &Rc<RefCell<Vec<u8>>>) -> Self { 330 let len = bytes.deref().borrow().len(); 331 Printer { 332 prompt: Prompt { 333 computer_name: "DragonOS".to_string(), 334 user_name: "root".to_string(), 335 path: std::env::current_dir() 336 .expect("Error getting current directory") 337 .to_str() 338 .unwrap() 339 .to_string(), 340 }, 341 buf: Rc::clone(bytes), 342 cursor: len, 343 } 344 } 345 346 fn init_before_readline(&mut self) { 347 self.buf = Rc::new(RefCell::new(Vec::new())); 348 self.prompt.update_path(); 349 self.print_prompt(); 350 self.cursor = 0; 351 self.flush_cursor(); 352 } 353 354 fn print_prompt(&self) { 355 print!("{}", self.prompt); 356 stdout().flush().unwrap(); 357 } 358 359 //在光标处插入字符串 360 fn insert(&mut self, bytes: &[u8]) { 361 let mut buf = self.buf.deref().borrow_mut(); 362 // self.delete_to_cursor(buf.len() - cursor); 363 // print!("{}"," ".repeat(buf.len() - cursor)); 364 Printer::print(bytes); 365 Printer::print(&buf[self.cursor..]); 366 buf.splice(self.cursor..self.cursor, bytes.iter().cloned()); 367 self.cursor += bytes.len(); 368 self.flush_cursor(); 369 stdout().flush().unwrap(); 370 } 371 372 //删除下标为[cursor,cursor + len)的字符,光标位置不变 373 fn delete(&self, len: usize) { 374 let cursor = self.cursor; 375 let mut buf = self.buf.deref().borrow_mut(); 376 if cursor + len - 1 < buf.len() { 377 Printer::print(&buf[cursor + len..]); 378 print!("{}", " ".repeat(len)); 379 self.flush_cursor(); 380 buf.drain(cursor..cursor + len); 381 stdout().flush().unwrap(); 382 } 383 } 384 385 fn backspace(&mut self) { 386 if self.cursor > 0 { 387 crossterm::execute!(io::stdout(), crossterm::cursor::MoveLeft(1)).unwrap(); 388 self.cursor -= 1; 389 self.flush_cursor(); 390 self.delete(1); 391 } 392 } 393 394 fn flush_cursor(&self) { 395 crossterm::execute!( 396 io::stdout(), 397 crossterm::cursor::MoveToColumn((self.cursor + self.prompt.len()) as u16) 398 ) 399 .unwrap(); 400 } 401 402 fn cursor_left(&mut self) { 403 if self.cursor > 0 { 404 crossterm::execute!(io::stdout(), crossterm::cursor::MoveLeft(1)).unwrap(); 405 self.cursor -= 1; 406 } 407 } 408 409 fn cursor_right(&mut self) { 410 let buf = self.buf.deref().borrow(); 411 if self.cursor < buf.len() { 412 crossterm::execute!(io::stdout(), crossterm::cursor::MoveRight(1)).unwrap(); 413 self.cursor += 1; 414 } 415 } 416 417 fn home(&mut self) { 418 self.cursor = 0; 419 self.flush_cursor(); 420 } 421 422 fn end(&mut self) { 423 self.cursor = self.buf.deref().borrow().len(); 424 self.flush_cursor(); 425 } 426 427 fn change_line(&mut self, new_buf: &Rc<RefCell<Vec<u8>>>) { 428 let old_buf_borrow = self.buf.deref().borrow(); 429 let new_buf_borrow = new_buf.deref().borrow(); 430 self.cursor = 0; 431 self.flush_cursor(); 432 Printer::print(&new_buf_borrow[..]); 433 self.cursor = new_buf_borrow.len(); 434 if new_buf_borrow.len() < old_buf_borrow.len() { 435 print!( 436 "{}", 437 " ".repeat(old_buf_borrow.len() - new_buf_borrow.len()) 438 ); 439 self.flush_cursor(); 440 } 441 drop(old_buf_borrow); 442 drop(new_buf_borrow); 443 self.buf = Rc::clone(new_buf); 444 stdout().flush().unwrap(); 445 } 446 447 fn print(bytes: &[u8]) { 448 print!("{}", String::from_utf8(bytes.to_vec()).unwrap()); 449 } 450 } 451 452 // 测试终端颜色显示效果 453 #[allow(dead_code)] 454 pub fn _print_color_example() { 455 let example = "abcdefghijklmnopqrstuvwxyz"; 456 println!("{}", example.bright_black()); 457 println!("{}", example.bright_blue()); 458 println!("{}", example.bright_cyan()); 459 println!("{}", example.bright_green()); 460 println!("{}", example.bright_magenta()); 461 println!("{}", example.bright_purple()); 462 println!("{}", example.bright_red()); 463 println!("{}", example.bright_white()); 464 println!("{}", example.bright_yellow()); 465 println!("{}", example.black()); 466 println!("{}", example.blue()); 467 println!("{}", example.cyan()); 468 println!("{}", example.green()); 469 println!("{}", example.magenta()); 470 println!("{}", example.purple()); 471 println!("{}", example.red()); 472 println!("{}", example.white()); 473 println!("{}", example.yellow()); 474 } 475 476 pub fn complete_command(command: &str) -> (&str, Vec<String>) { 477 let mut candidates: Vec<String> = Vec::new(); 478 for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD { 479 if cmd.starts_with(command) { 480 candidates.push(String::from(*cmd)); 481 } 482 } 483 ("", candidates) 484 } 485 486 pub fn complete_path(incomplete_path: &str) -> (&str, Vec<String>) { 487 let mut candidates: Vec<String> = Vec::new(); 488 let mut dir = ""; 489 let incomplete_name: &str; 490 if let Some(index) = incomplete_path.rfind('/') { 491 dir = &incomplete_path[..=index]; 492 incomplete_name = &incomplete_path[index + 1..]; 493 } else { 494 incomplete_name = incomplete_path; 495 } 496 if let Ok(read_dir) = fs::read_dir(if dir.is_empty() { "." } else { dir }) { 497 // if incomplete_name == "" { 498 // for entry in read_dir { 499 // let entry = entry.unwrap(); 500 // let mut file_name = entry.file_name().into_string().unwrap(); 501 // if entry.file_type().unwrap().is_dir() { 502 // file_name.push('/'); 503 // } 504 // candidates.push(file_name); 505 // } 506 // } else { 507 for entry in read_dir { 508 let entry = entry.unwrap(); 509 let mut file_name = entry.file_name().into_string().unwrap(); 510 if file_name.starts_with(incomplete_name) { 511 if file_name.contains(' ') { 512 file_name = format!("\'{}\'", file_name); 513 } 514 if entry.file_type().unwrap().is_dir() { 515 file_name.push('/'); 516 } 517 candidates.push(file_name); 518 } 519 } 520 // } 521 } 522 523 return (dir, candidates); 524 } 525