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 readline(&mut self) -> usize { 148 let mut stdout = std::io::stdout(); 149 self.history_commands.push(Rc::clone(&self.printer.buf)); 150 let mut command_index = self.history_commands.len() - 1; 151 loop { 152 let key = Self::read_char(); 153 if let Ok(special_key) = SpecialKeycode::try_from(key) { 154 match special_key { 155 SpecialKeycode::FunctionKeyPrefix => { 156 let key = Self::read_char(); 157 let function_key = FunctionKeySuffix::try_from(key).unwrap(); 158 match function_key { 159 FunctionKeySuffix::Up => { 160 if command_index > 0 { 161 command_index -= 1; 162 self.printer.change_line( 163 self.history_commands.get(command_index).unwrap(), 164 ); 165 } 166 } 167 168 FunctionKeySuffix::Down => { 169 if command_index < self.history_commands.len() - 1 { 170 command_index += 1; 171 self.printer.change_line( 172 self.history_commands.get(command_index).unwrap(), 173 ); 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 } 197 } 198 199 SpecialKeycode::LF | SpecialKeycode::CR => { 200 println!(); 201 self.history_commands.pop(); 202 return 1; 203 } 204 205 SpecialKeycode::BackSpace => { 206 self.printer.backspace(); 207 } 208 209 SpecialKeycode::Delete => { 210 self.printer.delete(1); 211 } 212 213 SpecialKeycode::Tab => { 214 let mut buf = self.printer.buf.deref().borrow().clone(); 215 buf.truncate(self.printer.cursor); 216 let str = String::from_utf8(buf.clone()).unwrap(); 217 if buf.len() == 0 || buf.iter().all(|byte| *byte == b' ') { 218 continue; 219 } 220 221 let iter = str.chars(); 222 let mut fragments: Vec<String> = Vec::new(); 223 let mut stack: String = String::with_capacity(str.len()); 224 let mut left_quote: char = ' '; 225 for ch in iter { 226 //存在未闭合的左引号,此时包括空格的任何字符都加入栈中,直到匹配到右引号 227 if left_quote != ' ' { 228 if ch == left_quote { 229 left_quote = ' '; 230 } 231 stack.push(ch); 232 } else { 233 //不存在未闭合的左引号 234 if ch == '\'' || ch == '\"' { 235 //字符为引号,记录下来 236 left_quote = ch; 237 stack.push(ch); 238 } else if ch == ' ' { 239 if !stack.is_empty() { 240 //字符为空格且栈中不为空,该空格视作命令段之间的分割线 241 //将栈中字符作为一个命令段加入集合,之后重置栈 242 fragments.push(stack.to_string()); 243 stack.clear(); 244 } 245 } else { 246 //其他字符都作为普通字符加入栈中 247 stack.push(ch); 248 } 249 } 250 } 251 //结束时如果栈不为空 252 if !stack.is_empty() { 253 fragments.push(stack.to_string()); 254 } else { 255 //结束时如果栈为空,说明光标左边的字符不属于任何命令片段,无法进行补全 256 return 1; 257 } 258 259 let mut target_fragment = fragments.last().unwrap().clone(); 260 target_fragment = target_fragment.replace("\'", "").replace("\"", ""); 261 262 let (prefix, candidates) = if fragments.len() < 2 { 263 //补全命令 264 complete_command(&target_fragment) 265 } else { 266 //补全参数 267 complete_path(&target_fragment) 268 }; 269 270 match candidates.len() { 271 1 => { 272 let old_fragment = fragments.last().unwrap(); 273 let candidate = candidates.last().unwrap(); 274 self.printer.cursor_left(old_fragment.len()); 275 self.printer.delete(old_fragment.len()); 276 self.printer 277 .insert(format!("{}{}", prefix, candidate).as_bytes()); 278 } 279 2.. => { 280 self.printer.end(); 281 println!(); 282 for candidate in candidates { 283 print!( 284 "{}\t", 285 if candidate.ends_with('/') { 286 candidate.truecolor(0x00, 0x88, 0xff) 287 } else { 288 candidate.white() 289 } 290 ); 291 } 292 println!(); 293 self.printer.print_prompt(); 294 print!( 295 "{}", 296 String::from_utf8(self.printer.buf.borrow().to_vec()).unwrap() 297 ); 298 } 299 _ => {} 300 } 301 } 302 303 _ => {} 304 } 305 } else { 306 match key { 307 1..=31 => {} 308 c => { 309 self.printer.insert(&[c]); 310 // String::from_utf8("abdsdf".as_bytes().to_vec()).unwrap(); 311 } 312 } 313 } 314 stdout.flush().unwrap(); 315 } 316 } 317 318 fn add_backend_task(&mut self, child: Child) { 319 let mut job_id = 1; 320 while self.backend_task.contains_key(&job_id) { 321 job_id += 1; 322 } 323 324 println!("[{}] {}", job_id, child.id()); 325 self.backend_task.insert(job_id, child); 326 } 327 328 fn detect_task_done(&mut self) { 329 self.backend_task.retain(|job_id, task| { 330 if let Ok(Some(status)) = task.try_wait() { 331 println!("[{}] done with status: {}", job_id, status); 332 false 333 } else { 334 true 335 } 336 }) 337 } 338 } 339 340 #[allow(dead_code)] 341 struct WindowSize { 342 row: usize, 343 col: usize, 344 } 345 346 impl WindowSize { 347 pub fn new() -> Option<Self> { 348 let mut ws: libc::winsize = unsafe { std::mem::zeroed() }; 349 if unsafe { 350 libc::ioctl( 351 libc::STDOUT_FILENO, 352 libc::TIOCGWINSZ, 353 &mut ws as *mut libc::winsize, 354 ) 355 } == -1 356 { 357 None 358 } else { 359 Some(Self { 360 row: ws.ws_row.into(), 361 col: ws.ws_col.into(), 362 }) 363 } 364 } 365 } 366 367 pub fn complete_command(command: &str) -> (&str, Vec<String>) { 368 let mut candidates: Vec<String> = Vec::new(); 369 for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD { 370 if cmd.starts_with(command) { 371 candidates.push(String::from(*cmd)); 372 } 373 } 374 ("", candidates) 375 } 376 377 pub fn complete_path(incomplete_path: &str) -> (&str, Vec<String>) { 378 let mut candidates: Vec<String> = Vec::new(); 379 let mut dir = ""; 380 let incomplete_name: &str; 381 if let Some(index) = incomplete_path.rfind('/') { 382 dir = &incomplete_path[..=index]; 383 incomplete_name = &incomplete_path[index + 1..]; 384 } else { 385 incomplete_name = incomplete_path; 386 } 387 if let Ok(read_dir) = fs::read_dir(if dir.is_empty() { "." } else { dir }) { 388 for entry in read_dir { 389 let entry = entry.unwrap(); 390 let mut file_name = entry.file_name().into_string().unwrap(); 391 if file_name.starts_with(incomplete_name) { 392 if file_name.contains(' ') { 393 file_name = format!("\'{}\'", file_name); 394 } 395 if entry.file_type().unwrap().is_dir() { 396 file_name.push('/'); 397 } 398 candidates.push(file_name); 399 } 400 } 401 } 402 403 return (dir, candidates); 404 } 405