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