|
@@ -1,9 +1,8 @@
|
|
|
use std::{
|
|
|
cell::RefCell,
|
|
|
collections::HashMap,
|
|
|
- fmt,
|
|
|
fs::{self, File, OpenOptions},
|
|
|
- io::{self, stdout, BufRead, BufReader, Read, Write},
|
|
|
+ io::{BufRead, BufReader, Read, Write},
|
|
|
ops::Deref,
|
|
|
path::Path,
|
|
|
print,
|
|
@@ -15,47 +14,21 @@ use crate::keycode::{FunctionKeySuffix, SpecialKeycode};
|
|
|
|
|
|
use colored::Colorize;
|
|
|
use command::{BuildInCmd, Command, CommandError};
|
|
|
+use printer::Printer;
|
|
|
|
|
|
-pub mod command;
|
|
|
-
|
|
|
-pub struct Prompt {
|
|
|
- user_name: String,
|
|
|
- computer_name: String,
|
|
|
- path: String,
|
|
|
-}
|
|
|
-
|
|
|
-impl Prompt {
|
|
|
- pub fn len(&self) -> usize {
|
|
|
- format!("{}@{}:{}$ ", self.user_name, self.computer_name, self.path).len()
|
|
|
- }
|
|
|
-
|
|
|
- pub fn update_path(&mut self) {
|
|
|
- self.path = std::env::current_dir()
|
|
|
- .unwrap()
|
|
|
- .to_str()
|
|
|
- .unwrap()
|
|
|
- .to_string();
|
|
|
- }
|
|
|
-}
|
|
|
+mod printer;
|
|
|
|
|
|
-impl fmt::Display for Prompt {
|
|
|
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
- write!(
|
|
|
- f,
|
|
|
- "{}:{}$ ",
|
|
|
- format!("{}@{}", self.user_name, self.computer_name).bright_green(),
|
|
|
- self.path.bright_cyan()
|
|
|
- )
|
|
|
- }
|
|
|
-}
|
|
|
+pub mod command;
|
|
|
|
|
|
const DEFAULT_HISTORY_COMMANDS_PATH: &str = "/history_commands.txt";
|
|
|
|
|
|
+#[allow(dead_code)]
|
|
|
pub struct Shell {
|
|
|
history_commands: Vec<Rc<RefCell<Vec<u8>>>>,
|
|
|
history_path: String,
|
|
|
printer: Printer,
|
|
|
backend_task: HashMap<usize, Child>,
|
|
|
+ window_size: Option<WindowSize>,
|
|
|
}
|
|
|
|
|
|
impl Shell {
|
|
@@ -65,6 +38,7 @@ impl Shell {
|
|
|
history_path: DEFAULT_HISTORY_COMMANDS_PATH.to_string(),
|
|
|
printer: Printer::new(&Rc::new(RefCell::new(Vec::new()))),
|
|
|
backend_task: HashMap::new(),
|
|
|
+ window_size: WindowSize::new(),
|
|
|
};
|
|
|
shell.read_commands();
|
|
|
shell
|
|
@@ -78,13 +52,17 @@ impl Shell {
|
|
|
}
|
|
|
|
|
|
pub fn exec(&mut self) {
|
|
|
+ // 开启终端raw模式
|
|
|
// 开启终端raw模式
|
|
|
crossterm::terminal::enable_raw_mode().expect("failed to enable raw mode");
|
|
|
|
|
|
+ // 循环读取一行
|
|
|
+
|
|
|
// 循环读取一行
|
|
|
loop {
|
|
|
self.printer.init_before_readline();
|
|
|
// 读取一行
|
|
|
+ // 读取一行
|
|
|
if self.readline() == 0 {
|
|
|
println!();
|
|
|
break;
|
|
@@ -92,6 +70,8 @@ impl Shell {
|
|
|
|
|
|
let command_bytes = self.printer.buf.borrow().clone();
|
|
|
|
|
|
+ // 如果命令不以空格开头且不跟上一条命令相同,这条命令会被记录
|
|
|
+
|
|
|
// 如果命令不以空格开头且不跟上一条命令相同,这条命令会被记录
|
|
|
if !command_bytes.is_empty()
|
|
|
&& !command_bytes.starts_with(&[b' '])
|
|
@@ -108,6 +88,8 @@ impl Shell {
|
|
|
self.write_commands(&command_bytes);
|
|
|
};
|
|
|
|
|
|
+ // 命令不为空,执行命令
|
|
|
+
|
|
|
// 命令不为空,执行命令
|
|
|
if !command_bytes.iter().all(|&byte| byte == b' ') {
|
|
|
self.exec_commands_in_line(&command_bytes);
|
|
@@ -193,11 +175,15 @@ impl Shell {
|
|
|
}
|
|
|
|
|
|
FunctionKeySuffix::Left => {
|
|
|
- self.printer.cursor_left();
|
|
|
+ if self.printer.cursor > 0 {
|
|
|
+ self.printer.cursor_left(1);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
FunctionKeySuffix::Right => {
|
|
|
- self.printer.cursor_right();
|
|
|
+ if self.printer.cursor < self.printer.buf.borrow().len() {
|
|
|
+ self.printer.cursor_right(1);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
FunctionKeySuffix::Home => {
|
|
@@ -285,14 +271,12 @@ impl Shell {
|
|
|
1 => {
|
|
|
let old_fragment = fragments.last().unwrap();
|
|
|
let candidate = candidates.last().unwrap();
|
|
|
- self.printer.cursor -= old_fragment.len();
|
|
|
- self.printer.flush_cursor();
|
|
|
+ self.printer.cursor_left(old_fragment.len());
|
|
|
self.printer.delete(old_fragment.len());
|
|
|
self.printer
|
|
|
.insert(format!("{}{}", prefix, candidate).as_bytes());
|
|
|
}
|
|
|
2.. => {
|
|
|
- let old_cursor = self.printer.cursor;
|
|
|
self.printer.end();
|
|
|
println!();
|
|
|
for candidate in candidates {
|
|
@@ -307,9 +291,10 @@ impl Shell {
|
|
|
}
|
|
|
println!();
|
|
|
self.printer.print_prompt();
|
|
|
- Printer::print(&self.printer.buf.deref().borrow());
|
|
|
- self.printer.cursor = old_cursor;
|
|
|
- self.printer.flush_cursor();
|
|
|
+ print!(
|
|
|
+ "{}",
|
|
|
+ String::from_utf8(self.printer.buf.borrow().to_vec()).unwrap()
|
|
|
+ );
|
|
|
}
|
|
|
_ => {}
|
|
|
}
|
|
@@ -322,6 +307,7 @@ impl Shell {
|
|
|
1..=31 => {}
|
|
|
c => {
|
|
|
self.printer.insert(&[c]);
|
|
|
+ // String::from_utf8("abdsdf".as_bytes().to_vec()).unwrap();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -351,164 +337,33 @@ impl Shell {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-struct Printer {
|
|
|
- /// 提示语
|
|
|
- prompt: Prompt,
|
|
|
- /// 缓存区,记录当前显示的内容
|
|
|
- buf: Rc<RefCell<Vec<u8>>>,
|
|
|
- /// 光标位置(不包括提示语)
|
|
|
- cursor: usize,
|
|
|
+#[allow(dead_code)]
|
|
|
+struct WindowSize {
|
|
|
+ row: usize,
|
|
|
+ col: usize,
|
|
|
}
|
|
|
|
|
|
-impl Printer {
|
|
|
- fn new(bytes: &Rc<RefCell<Vec<u8>>>) -> Self {
|
|
|
- let len = bytes.deref().borrow().len();
|
|
|
- Printer {
|
|
|
- prompt: Prompt {
|
|
|
- computer_name: "DragonOS".to_string(),
|
|
|
- user_name: "root".to_string(),
|
|
|
- path: std::env::current_dir()
|
|
|
- .expect("Error getting current directory")
|
|
|
- .to_str()
|
|
|
- .unwrap()
|
|
|
- .to_string(),
|
|
|
- },
|
|
|
- buf: Rc::clone(bytes),
|
|
|
- cursor: len,
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// 读取输入前初始化信息
|
|
|
- fn init_before_readline(&mut self) {
|
|
|
- self.buf = Rc::new(RefCell::new(Vec::new()));
|
|
|
- self.prompt.update_path();
|
|
|
- self.print_prompt();
|
|
|
- self.cursor = 0;
|
|
|
- self.flush_cursor();
|
|
|
- }
|
|
|
-
|
|
|
- fn print_prompt(&self) {
|
|
|
- print!("{}", self.prompt);
|
|
|
- stdout().flush().unwrap();
|
|
|
- }
|
|
|
-
|
|
|
- /// 在光标处插入字符串
|
|
|
- fn insert(&mut self, bytes: &[u8]) {
|
|
|
- let mut buf = self.buf.deref().borrow_mut();
|
|
|
- // self.delete_to_cursor(buf.len() - cursor);
|
|
|
- // print!("{}"," ".repeat(buf.len() - cursor));
|
|
|
- Printer::print(bytes);
|
|
|
- Printer::print(&buf[self.cursor..]);
|
|
|
- buf.splice(self.cursor..self.cursor, bytes.iter().cloned());
|
|
|
- self.cursor += bytes.len();
|
|
|
- self.flush_cursor();
|
|
|
- stdout().flush().unwrap();
|
|
|
- }
|
|
|
-
|
|
|
- /// 删除下标为[cursor,cursor + len)的字符,光标位置不变
|
|
|
- fn delete(&self, len: usize) {
|
|
|
- let cursor = self.cursor;
|
|
|
- let mut buf = self.buf.deref().borrow_mut();
|
|
|
- if cursor + len - 1 < buf.len() {
|
|
|
- Printer::print(&buf[cursor + len..]);
|
|
|
- print!("{}", " ".repeat(len));
|
|
|
- self.flush_cursor();
|
|
|
- buf.drain(cursor..cursor + len);
|
|
|
- stdout().flush().unwrap();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn backspace(&mut self) {
|
|
|
- if self.cursor > 0 {
|
|
|
- crossterm::execute!(io::stdout(), crossterm::cursor::MoveLeft(1)).unwrap();
|
|
|
- self.cursor -= 1;
|
|
|
- self.flush_cursor();
|
|
|
- self.delete(1);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn flush_cursor(&self) {
|
|
|
- crossterm::execute!(
|
|
|
- io::stdout(),
|
|
|
- crossterm::cursor::MoveToColumn((self.cursor + self.prompt.len()) as u16)
|
|
|
- )
|
|
|
- .unwrap();
|
|
|
- }
|
|
|
-
|
|
|
- fn cursor_left(&mut self) {
|
|
|
- if self.cursor > 0 {
|
|
|
- crossterm::execute!(io::stdout(), crossterm::cursor::MoveLeft(1)).unwrap();
|
|
|
- self.cursor -= 1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn cursor_right(&mut self) {
|
|
|
- let buf = self.buf.deref().borrow();
|
|
|
- if self.cursor < buf.len() {
|
|
|
- crossterm::execute!(io::stdout(), crossterm::cursor::MoveRight(1)).unwrap();
|
|
|
- self.cursor += 1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn home(&mut self) {
|
|
|
- self.cursor = 0;
|
|
|
- self.flush_cursor();
|
|
|
- }
|
|
|
-
|
|
|
- fn end(&mut self) {
|
|
|
- self.cursor = self.buf.deref().borrow().len();
|
|
|
- self.flush_cursor();
|
|
|
- }
|
|
|
-
|
|
|
- fn change_line(&mut self, new_buf: &Rc<RefCell<Vec<u8>>>) {
|
|
|
- let old_buf_borrow = self.buf.deref().borrow();
|
|
|
- let new_buf_borrow = new_buf.deref().borrow();
|
|
|
- self.cursor = 0;
|
|
|
- self.flush_cursor();
|
|
|
- Printer::print(&new_buf_borrow[..]);
|
|
|
- self.cursor = new_buf_borrow.len();
|
|
|
- if new_buf_borrow.len() < old_buf_borrow.len() {
|
|
|
- print!(
|
|
|
- "{}",
|
|
|
- " ".repeat(old_buf_borrow.len() - new_buf_borrow.len())
|
|
|
- );
|
|
|
- self.flush_cursor();
|
|
|
+impl WindowSize {
|
|
|
+ pub fn new() -> Option<Self> {
|
|
|
+ let mut ws: libc::winsize = unsafe { std::mem::zeroed() };
|
|
|
+ if unsafe {
|
|
|
+ libc::ioctl(
|
|
|
+ libc::STDOUT_FILENO,
|
|
|
+ libc::TIOCGWINSZ,
|
|
|
+ &mut ws as *mut libc::winsize,
|
|
|
+ )
|
|
|
+ } == -1
|
|
|
+ {
|
|
|
+ None
|
|
|
+ } else {
|
|
|
+ Some(Self {
|
|
|
+ row: ws.ws_row.into(),
|
|
|
+ col: ws.ws_col.into(),
|
|
|
+ })
|
|
|
}
|
|
|
- drop(old_buf_borrow);
|
|
|
- drop(new_buf_borrow);
|
|
|
- self.buf = Rc::clone(new_buf);
|
|
|
- stdout().flush().unwrap();
|
|
|
- }
|
|
|
-
|
|
|
- fn print(bytes: &[u8]) {
|
|
|
- print!("{}", String::from_utf8(bytes.to_vec()).unwrap());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 测试终端颜色显示效果
|
|
|
-#[allow(dead_code)]
|
|
|
-pub fn _print_color_example() {
|
|
|
- let example = "abcdefghijklmnopqrstuvwxyz";
|
|
|
- println!("{}", example.bright_black());
|
|
|
- println!("{}", example.bright_blue());
|
|
|
- println!("{}", example.bright_cyan());
|
|
|
- println!("{}", example.bright_green());
|
|
|
- println!("{}", example.bright_magenta());
|
|
|
- println!("{}", example.bright_purple());
|
|
|
- println!("{}", example.bright_red());
|
|
|
- println!("{}", example.bright_white());
|
|
|
- println!("{}", example.bright_yellow());
|
|
|
- println!("{}", example.black());
|
|
|
- println!("{}", example.blue());
|
|
|
- println!("{}", example.cyan());
|
|
|
- println!("{}", example.green());
|
|
|
- println!("{}", example.magenta());
|
|
|
- println!("{}", example.purple());
|
|
|
- println!("{}", example.red());
|
|
|
- println!("{}", example.white());
|
|
|
- println!("{}", example.yellow());
|
|
|
-}
|
|
|
-
|
|
|
pub fn complete_command(command: &str) -> (&str, Vec<String>) {
|
|
|
let mut candidates: Vec<String> = Vec::new();
|
|
|
for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD {
|
|
@@ -530,16 +385,6 @@ pub fn complete_path(incomplete_path: &str) -> (&str, Vec<String>) {
|
|
|
incomplete_name = incomplete_path;
|
|
|
}
|
|
|
if let Ok(read_dir) = fs::read_dir(if dir.is_empty() { "." } else { dir }) {
|
|
|
- // if incomplete_name == "" {
|
|
|
- // for entry in read_dir {
|
|
|
- // let entry = entry.unwrap();
|
|
|
- // let mut file_name = entry.file_name().into_string().unwrap();
|
|
|
- // if entry.file_type().unwrap().is_dir() {
|
|
|
- // file_name.push('/');
|
|
|
- // }
|
|
|
- // candidates.push(file_name);
|
|
|
- // }
|
|
|
- // } else {
|
|
|
for entry in read_dir {
|
|
|
let entry = entry.unwrap();
|
|
|
let mut file_name = entry.file_name().into_string().unwrap();
|
|
@@ -553,7 +398,6 @@ pub fn complete_path(incomplete_path: &str) -> (&str, Vec<String>) {
|
|
|
candidates.push(file_name);
|
|
|
}
|
|
|
}
|
|
|
- // }
|
|
|
}
|
|
|
|
|
|
return (dir, candidates);
|