moros/src/user/shell.rs

182 lines
7.3 KiB
Rust
Raw Normal View History

2019-12-31 12:10:03 +00:00
use crate::{print, user, kernel};
2019-12-29 13:43:36 +00:00
use heapless::{String, FnvIndexSet, Vec};
2019-12-29 09:34:08 +00:00
use heapless::consts::*;
2019-12-28 17:08:11 +00:00
2020-01-01 08:07:09 +00:00
#[repr(u8)]
pub enum ExitCode {
CommandSuccessful = 0,
CommandUnknown = 1,
CommandError = 2,
ShellExit = 255,
}
2019-12-31 12:10:03 +00:00
pub struct Shell {
cmd: String<U256>,
history: FnvIndexSet<String<U256>, U256>,
history_index: usize,
2019-12-28 17:08:11 +00:00
}
2019-12-31 12:10:03 +00:00
impl Shell {
pub fn new() -> Self {
Shell {
cmd: String::new(),
history: FnvIndexSet::new(),
history_index: 0,
}
}
2019-12-29 13:43:36 +00:00
2020-01-01 08:07:09 +00:00
pub fn run(&mut self) -> user::shell::ExitCode {
2019-12-31 12:10:03 +00:00
self.print_prompt();
loop {
let c = kernel::console::get_char();
match c {
2019-12-31 17:16:52 +00:00
'\0' => {
2019-12-31 12:10:03 +00:00
continue;
2019-12-29 09:34:08 +00:00
}
2019-12-31 17:16:52 +00:00
'\n' => {
2019-12-31 12:10:03 +00:00
print!("\n");
2019-12-31 22:14:17 +00:00
if self.cmd.len() > 0 {
// Remove first command from history if full
if self.history.len() == self.history.capacity() {
let first = self.history.iter().next().unwrap().clone();
self.history.remove(&first);
}
2019-12-31 22:12:51 +00:00
2019-12-31 22:14:17 +00:00
// Add or move command to history at the end
let cmd = self.cmd.clone();
self.history.remove(&cmd);
if self.history.insert(cmd).is_ok() {
self.history_index = self.history.len();
}
2019-12-31 12:10:03 +00:00
let line = self.cmd.clone();
2020-01-01 08:07:09 +00:00
match self.exec(&line) {
ExitCode::CommandSuccessful => {},
ExitCode::ShellExit => { return ExitCode::CommandSuccessful },
_ => { print!("?\n") },
2019-12-31 12:10:03 +00:00
}
self.cmd.clear();
}
self.print_prompt();
},
2019-12-31 17:16:52 +00:00
'\x08' => { // Backspace
2019-12-31 12:10:03 +00:00
if self.cmd.len() > 0 {
self.cmd.pop();
2019-12-29 09:34:08 +00:00
print!("\x08");
}
2019-12-31 12:10:03 +00:00
},
2020-01-05 21:25:15 +00:00
'\x03' => { // Ctrl C
return ExitCode::CommandSuccessful;
},
2019-12-31 17:16:52 +00:00
'↑' => { // Arrow up
2019-12-31 12:10:03 +00:00
if self.history.len() > 0 {
if self.history_index > 0 {
self.history_index -= 1;
}
if let Some(cmd) = self.history.iter().nth(self.history_index) {
let n = self.cmd.len();
for _ in 0..n {
print!("\x08");
}
self.cmd = cmd.clone();
print!("{}", cmd);
}
}
},
2019-12-31 17:16:52 +00:00
'↓' => { // Arrow down
2019-12-31 12:10:03 +00:00
if self.history.len() > 0 {
if self.history_index < self.history.len() - 1 {
self.history_index += 1;
}
if let Some(cmd) = self.history.iter().nth(self.history_index) {
let n = self.cmd.len();
for _ in 0..n {
print!("\x08");
}
self.cmd = cmd.clone();
print!("{}", self.cmd);
}
}
},
2019-12-31 17:16:52 +00:00
c => {
if c.is_ascii_graphic() || c.is_ascii_whitespace() {
if self.cmd.push(c).is_ok() {
print!("{}", c);
}
2019-12-31 12:10:03 +00:00
}
},
2019-12-29 09:34:08 +00:00
}
2019-12-31 12:10:03 +00:00
}
}
2020-01-01 08:07:09 +00:00
pub fn exec(&self, cmd: &str) -> ExitCode {
let args: Vec<&str, U256> = cmd.split_whitespace().collect();
match args[0] {
"a" | "alias" => ExitCode::CommandUnknown,
"b" => ExitCode::CommandUnknown,
"c" | "copy" | "cp" => ExitCode::CommandUnknown,
"d" | "del" | "delete" | "rm" => ExitCode::CommandUnknown,
2020-01-01 10:37:12 +00:00
"e" | "edit" | "editor" => user::editor::main(&args),
2020-01-01 08:07:09 +00:00
"f" | "find" => ExitCode::CommandUnknown,
"g" | "gd" | "go" | "go-dir" | "cd" => ExitCode::CommandUnknown,
"h" | "help" => ExitCode::CommandUnknown,
"i" => ExitCode::CommandUnknown,
"j" | "jd" | "jump" | "jump-dir" => ExitCode::CommandUnknown,
"k" | "kill" => ExitCode::CommandUnknown,
"l" | "list" | "ls" => ExitCode::CommandUnknown,
"m" | "move" | "mv" => user::r#move::main(&args),
"n" => ExitCode::CommandUnknown,
"o" => ExitCode::CommandUnknown,
"p" | "print" | "echo" => user::print::main(&args),
"q" | "quit" | "exit" => ExitCode::ShellExit,
"r" | "read" | "cat" => user::read::main(&args),
"s" => ExitCode::CommandUnknown,
"t" | "tag" => ExitCode::CommandUnknown,
"u" => ExitCode::CommandUnknown,
"v" => ExitCode::CommandUnknown,
"w" | "write" => user::write::main(&args),
"x" => ExitCode::CommandUnknown,
"y" => ExitCode::CommandUnknown,
"z" => ExitCode::CommandUnknown,
"rd" | "read-dir" => ExitCode::CommandUnknown,
"wd" | "write-dir" | "mkdir" => ExitCode::CommandUnknown,
2020-01-01 08:07:24 +00:00
"shell" => user::shell::main(&args),
2020-01-01 08:07:09 +00:00
"sleep" => user::sleep::main(&args),
"clear" => user::clear::main(&args),
2020-01-01 08:54:54 +00:00
"login" => user::login::main(&args),
2020-01-03 21:01:48 +00:00
"base64" => user::base64::main(&args),
2020-01-01 08:07:09 +00:00
_ => ExitCode::CommandUnknown,
}
}
2019-12-31 12:10:03 +00:00
fn print_prompt(&self) {
print!("\n> ");
2019-12-28 17:08:11 +00:00
}
}
2020-01-01 08:07:24 +00:00
pub fn main(args: &[&str]) -> ExitCode {
let mut shell = Shell::new();
match args.len() {
1 => {
return shell.run();
},
2 => {
let pathname = args[1];
if let Some(file) = kernel::fs::File::open(pathname) {
for line in file.read().split("\n") {
2020-01-01 08:55:33 +00:00
if line.len() > 0 {
shell.exec(line);
}
2020-01-01 08:07:24 +00:00
}
ExitCode::CommandSuccessful
} else {
print!("File not found '{}'\n", pathname);
ExitCode::CommandError
}
},
_ => {
ExitCode::CommandError
},
}
}