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 {
|
2019-12-31 20:20:59 +00:00
|
|
|
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
|
|
|
},
|
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,
|
|
|
|
"e" | "edit" => ExitCode::CommandUnknown,
|
|
|
|
"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,
|
|
|
|
"sleep" => user::sleep::main(&args),
|
|
|
|
"clear" => user::clear::main(&args),
|
|
|
|
_ => ExitCode::CommandUnknown,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-31 12:10:03 +00:00
|
|
|
fn print_prompt(&self) {
|
|
|
|
print!("\n> ");
|
2019-12-28 17:08:11 +00:00
|
|
|
}
|
|
|
|
}
|