1 use std::{ 2 cell::RefCell, 3 collections::HashMap, 4 fs::{self, File, OpenOptions}, 5 io::{BufRead, BufReader, Read, Write}, 6 ops::Deref, 7 path::Path, 8 print, 9 process::Child, 10 rc::Rc, 11 }; 12 13 use crate::keycode::{FunctionKeySuffix, SpecialKeycode}; 14 15 use colored::Colorize; 16 use command::{BuildInCmd, Command, CommandError}; 17 use printer::Printer; 18 19 mod printer; 20 21 pub mod command; 22 23 const DEFAULT_HISTORY_COMMANDS_PATH: &str = "/history_commands.txt"; 24 25 #[allow(dead_code)] 26 pub struct Shell { 27 history_commands: Vec<Rc<RefCell<Vec<u8>>>>, 28 history_path: String, 29 printer: Printer, 30 backend_task: HashMap<usize, Child>, 31 window_size: Option<WindowSize>, 32 } 33 34 impl Shell { 35 pub fn new() -> Shell { 36 let mut shell = Shell { 37 history_commands: Vec::new(), 38 history_path: DEFAULT_HISTORY_COMMANDS_PATH.to_string(), 39 printer: Printer::new(&Rc::new(RefCell::new(Vec::new()))), 40 backend_task: HashMap::new(), 41 window_size: WindowSize::new(), 42 }; 43 shell.read_commands(); 44 shell 45 } 46 47 pub fn chdir(&mut self, new_dir: &String) { 48 let path = Path::new(&new_dir); 49 if let Err(e) = std::env::set_current_dir(&path) { 50 eprintln!("Error changing directory: {}", e); 51 } 52 } 53 54 pub fn exec(&mut self) { 55 // 开启终端raw模式 56 // 开启终端raw模式 57 crossterm::terminal::enable_raw_mode().expect("failed to enable raw mode"); 58 59 // 循环读取一行 60 61 // 循环读取一行 62 loop { 63 self.printer.init_before_readline(); 64 // 读取一行 65 // 读取一行 66 if self.readline() == 0 { 67 println!(); 68 break; 69 } 70 71 let command_bytes = self.printer.buf.borrow().clone(); 72 73 // 如果命令不以空格开头且不跟上一条命令相同,这条命令会被记录 74 75 // 如果命令不以空格开头且不跟上一条命令相同,这条命令会被记录 76 if !command_bytes.is_empty() 77 && !command_bytes.starts_with(&[b' ']) 78 && command_bytes 79 != self 80 .history_commands 81 .last() 82 .unwrap_or(&Rc::new(RefCell::new(Vec::new()))) 83 .borrow() 84 .clone() 85 { 86 self.history_commands 87 .push(Rc::new(RefCell::new(command_bytes.clone()))); 88 self.write_commands(&command_bytes); 89 }; 90 91 // 命令不为空,执行命令 92 93 // 命令不为空,执行命令 94 if !command_bytes.iter().all(|&byte| byte == b' ') { 95 self.exec_commands_in_line(&command_bytes); 96 } 97 self.detect_task_done(); 98 } 99 } 100 101 fn exec_commands_in_line(&mut self, command_bytes: &Vec<u8>) { 102 match Command::parse(String::from_utf8(command_bytes.clone()).unwrap()) { 103 Ok(commands) => commands 104 .into_iter() 105 .for_each(|command| self.exec_command(command)), 106 Err(e) => CommandError::handle(e), 107 } 108 } 109 110 pub fn read_commands(&mut self) { 111 let mut history = Vec::new(); 112 for line in BufReader::new(match File::open(&self.history_path) { 113 Ok(file) => file, 114 Err(_) => File::create(&self.history_path).unwrap(), 115 }) 116 .lines() 117 { 118 match line { 119 Ok(s) => history.push(Rc::new(RefCell::new(s.into_bytes()))), 120 Err(_) => { 121 break; 122 } 123 } 124 } 125 self.history_commands = history; 126 } 127 128 fn write_commands(&self, command_bytes: &Vec<u8>) { 129 let mut file = OpenOptions::new() 130 .append(true) 131 .open(self.history_path.as_str()) 132 .unwrap(); 133 file.write_all(&command_bytes) 134 .expect("failed to write history command"); 135 file.write_all(&[SpecialKeycode::LF.into()]).unwrap(); 136 } 137 138 fn read_char() -> u8 { 139 let mut buf: [u8; 1] = [0]; 140 loop { 141 if std::io::stdin().read(&mut buf).is_ok() { 142 return buf[0]; 143 } 144 } 145 } 146 147 fn handle_funckey(&mut self, command_index: &mut usize) { 148 let mut keys = Vec::new(); 149 150 while FunctionKeySuffix::should_read_more(&keys) { 151 keys.push(Self::read_char()); 152 } 153 let function_key = FunctionKeySuffix::try_from(&keys); 154 if function_key.is_none() { 155 return; 156 } 157 158 let function_key = function_key.unwrap(); 159 160 match function_key { 161 FunctionKeySuffix::Up => { 162 if *command_index > 0 { 163 *command_index -= 1; 164 self.printer 165 .change_line(self.history_commands.get(*command_index).unwrap()); 166 } 167 } 168 169 FunctionKeySuffix::Down => { 170 if *command_index < self.history_commands.len() - 1 { 171 *command_index += 1; 172 self.printer 173 .change_line(self.history_commands.get(*command_index).unwrap()); 174 } 175 } 176 177 FunctionKeySuffix::Left => { 178 if self.printer.cursor > 0 { 179 self.printer.cursor_left(1); 180 } 181 } 182 183 FunctionKeySuffix::Right => { 184 if self.printer.cursor < self.printer.buf.borrow().len() { 185 self.printer.cursor_right(1); 186 } 187 } 188 189 FunctionKeySuffix::Home => { 190 self.printer.home(); 191 } 192 193 FunctionKeySuffix::End => { 194 self.printer.end(); 195 } 196 FunctionKeySuffix::Delete => self.printer.delete(1), 197 } 198 } 199 200 fn readline(&mut self) -> usize { 201 let mut stdout = std::io::stdout(); 202 self.history_commands.push(Rc::clone(&self.printer.buf)); 203 let mut command_index = self.history_commands.len() - 1; 204 loop { 205 let key = Self::read_char(); 206 if let Ok(special_key) = SpecialKeycode::try_from(key) { 207 match special_key { 208 SpecialKeycode::ESC => { 209 self.handle_funckey(&mut command_index); 210 } 211 212 SpecialKeycode::LF | SpecialKeycode::CR => { 213 println!(); 214 self.history_commands.pop(); 215 return 1; 216 } 217 218 SpecialKeycode::BackSpace => { 219 self.printer.backspace(); 220 } 221 222 SpecialKeycode::Tab => { 223 let mut buf = self.printer.buf.deref().borrow().clone(); 224 buf.truncate(self.printer.cursor); 225 let str = String::from_utf8(buf.clone()).unwrap(); 226 if buf.len() == 0 || buf.iter().all(|byte| *byte == b' ') { 227 continue; 228 } 229 230 let iter = str.chars(); 231 let mut fragments: Vec<String> = Vec::new(); 232 let mut stack: String = String::with_capacity(str.len()); 233 let mut left_quote: char = ' '; 234 for ch in iter { 235 //存在未闭合的左引号,此时包括空格的任何字符都加入栈中,直到匹配到右引号 236 if left_quote != ' ' { 237 if ch == left_quote { 238 left_quote = ' '; 239 } 240 stack.push(ch); 241 } else { 242 //不存在未闭合的左引号 243 if ch == '\'' || ch == '\"' { 244 //字符为引号,记录下来 245 left_quote = ch; 246 stack.push(ch); 247 } else if ch == ' ' { 248 if !stack.is_empty() { 249 //字符为空格且栈中不为空,该空格视作命令段之间的分割线 250 //将栈中字符作为一个命令段加入集合,之后重置栈 251 fragments.push(stack.to_string()); 252 stack.clear(); 253 } 254 } else { 255 //其他字符都作为普通字符加入栈中 256 stack.push(ch); 257 } 258 } 259 } 260 //结束时如果栈不为空 261 if !stack.is_empty() { 262 fragments.push(stack.to_string()); 263 } else { 264 //结束时如果栈为空,说明光标左边的字符不属于任何命令片段,无法进行补全 265 return 1; 266 } 267 268 let mut target_fragment = fragments.last().unwrap().clone(); 269 target_fragment = target_fragment.replace("\'", "").replace("\"", ""); 270 271 let (prefix, candidates) = if fragments.len() < 2 { 272 //补全命令 273 complete_command(&target_fragment) 274 } else { 275 //补全参数 276 complete_path(&target_fragment) 277 }; 278 279 match candidates.len() { 280 1 => { 281 let old_fragment = fragments.last().unwrap(); 282 let candidate = candidates.last().unwrap(); 283 self.printer.cursor_left(old_fragment.len()); 284 self.printer.delete(old_fragment.len()); 285 self.printer 286 .insert(format!("{}{}", prefix, candidate).as_bytes()); 287 } 288 2.. => { 289 self.printer.end(); 290 println!(); 291 for candidate in candidates { 292 print!( 293 "{}\t", 294 if candidate.ends_with('/') { 295 candidate.truecolor(0x00, 0x88, 0xff) 296 } else { 297 candidate.white() 298 } 299 ); 300 } 301 println!(); 302 self.printer.print_prompt(); 303 print!( 304 "{}", 305 String::from_utf8(self.printer.buf.borrow().to_vec()).unwrap() 306 ); 307 } 308 _ => {} 309 } 310 } 311 312 _ => {} 313 } 314 } else { 315 match key { 316 1..=31 => {} 317 c => { 318 self.printer.insert(&[c]); 319 // String::from_utf8("abdsdf".as_bytes().to_vec()).unwrap(); 320 } 321 } 322 } 323 stdout.flush().unwrap(); 324 } 325 } 326 327 fn add_backend_task(&mut self, child: Child) { 328 let mut job_id = 1; 329 while self.backend_task.contains_key(&job_id) { 330 job_id += 1; 331 } 332 333 println!("[{}] {}", job_id, child.id()); 334 self.backend_task.insert(job_id, child); 335 } 336 337 fn detect_task_done(&mut self) { 338 self.backend_task.retain(|job_id, task| { 339 if let Ok(Some(status)) = task.try_wait() { 340 println!("[{}] done with status: {}", job_id, status); 341 false 342 } else { 343 true 344 } 345 }) 346 } 347 } 348 349 #[allow(dead_code)] 350 struct WindowSize { 351 row: usize, 352 col: usize, 353 } 354 355 impl WindowSize { 356 pub fn new() -> Option<Self> { 357 let mut ws: libc::winsize = unsafe { std::mem::zeroed() }; 358 if unsafe { 359 libc::ioctl( 360 libc::STDOUT_FILENO, 361 libc::TIOCGWINSZ, 362 &mut ws as *mut libc::winsize, 363 ) 364 } == -1 365 { 366 None 367 } else { 368 Some(Self { 369 row: ws.ws_row.into(), 370 col: ws.ws_col.into(), 371 }) 372 } 373 } 374 } 375 376 pub fn complete_command(command: &str) -> (&str, Vec<String>) { 377 let mut candidates: Vec<String> = Vec::new(); 378 for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD { 379 if cmd.starts_with(command) { 380 candidates.push(String::from(*cmd)); 381 } 382 } 383 ("", candidates) 384 } 385 386 pub fn complete_path(incomplete_path: &str) -> (&str, Vec<String>) { 387 let mut candidates: Vec<String> = Vec::new(); 388 let mut dir = ""; 389 let incomplete_name: &str; 390 if let Some(index) = incomplete_path.rfind('/') { 391 dir = &incomplete_path[..=index]; 392 incomplete_name = &incomplete_path[index + 1..]; 393 } else { 394 incomplete_name = incomplete_path; 395 } 396 if let Ok(read_dir) = fs::read_dir(if dir.is_empty() { "." } else { dir }) { 397 for entry in read_dir { 398 let entry = entry.unwrap(); 399 let mut file_name = entry.file_name().into_string().unwrap(); 400 if file_name.starts_with(incomplete_name) { 401 if file_name.contains(' ') { 402 file_name = format!("\'{}\'", file_name); 403 } 404 if entry.file_type().unwrap().is_dir() { 405 file_name.push('/'); 406 } 407 candidates.push(file_name); 408 } 409 } 410 } 411 412 return (dir, candidates); 413 } 414