added custom directory support
This allows you to specifcy things such as `/bin` to pull commands from. It even kind of works
This commit is contained in:
parent
50173b1ed5
commit
e57e7ff907
107
src/main.rs
107
src/main.rs
@ -1,5 +1,6 @@
|
||||
#![feature(iter_intersperse)]
|
||||
use std::io::{BufRead, Write};
|
||||
#![feature(trait_alias)]
|
||||
use std::{fs, io::{BufRead, Write}, path::Path, process::{self, Stdio}};
|
||||
|
||||
fn main() {
|
||||
|
||||
@ -9,6 +10,9 @@ fn main() {
|
||||
let stdout = std::io::stdout();
|
||||
let mut out_lock = stdout.lock();
|
||||
|
||||
let commands = &Command::commands();
|
||||
println!("Loaded {} commands", commands.len());
|
||||
|
||||
loop {
|
||||
|
||||
let mut buf = String::new();
|
||||
@ -18,58 +22,44 @@ fn main() {
|
||||
out_lock.flush().unwrap();
|
||||
|
||||
in_lock.read_line(&mut buf).expect("Failed to read in to buffer.");
|
||||
let trim = buf.trim();
|
||||
let trimmed_input = buf.trim();
|
||||
|
||||
if let Some(choice) = Command::choose(trim, &commands()) {
|
||||
let words = trim.split(' ').collect::<Vec<&str>>();
|
||||
let o_choice = Command::choose(trimmed_input, commands);
|
||||
if let Some(choice) = o_choice {
|
||||
let words = trimmed_input.split(' ').collect::<Vec<&str>>();
|
||||
choice.call(words);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn commands() -> Vec<Command> {
|
||||
|
||||
let commands = vec![
|
||||
Command::init("ls", vec![], nil),
|
||||
Command::init("exit", vec![], |_| {
|
||||
std::process::exit(0);
|
||||
}),
|
||||
Command::init("echo", vec![], |f| {
|
||||
let msg = &f[1..].iter().map(|s| s.to_owned()).intersperse(" ").collect::<String>();
|
||||
println!("{msg}");
|
||||
}),
|
||||
];
|
||||
|
||||
commands
|
||||
}
|
||||
|
||||
type Param<'a> = Vec<&'a str>;
|
||||
type Run = fn(Param) -> ();
|
||||
fn nil(_: Param) {}
|
||||
trait Run = Fn(Param);
|
||||
type Cmd = Box<dyn Run>;
|
||||
|
||||
#[derive(Debug)]
|
||||
// #[derive(Debug)]
|
||||
struct Command {
|
||||
name: String,
|
||||
sub_commands: Vec<Command>,
|
||||
cmd: Run,
|
||||
_sub_commands: Vec<Command>,
|
||||
cmd: Cmd,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
fn init(name: &str, sub_commands: Vec<Command>, f: Run) -> Self {
|
||||
fn init<T>(name: T, sub_commands: Vec<Self>, f: Cmd) -> Self where T: ToString {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
sub_commands,
|
||||
_sub_commands: sub_commands,
|
||||
cmd: f,
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&self, words: Param) {
|
||||
let x = self.cmd;
|
||||
let x = &self.cmd;
|
||||
x(words)
|
||||
}
|
||||
|
||||
fn choose<'a>(text: &str, choices: &'a Vec<Command>) -> Option<&'a Command> {
|
||||
fn choose<'a>(text: &str, choices: &'a Vec<Self>) -> Option<&'a Self> {
|
||||
|
||||
// TODO there seems to be duplicates in here?
|
||||
|
||||
// See what command the user is trying to call
|
||||
// iter thru all the commands
|
||||
@ -88,7 +78,10 @@ impl Command {
|
||||
|
||||
if ranked.len() > 1 {
|
||||
// If the top two command choices are ranked the same, we don't know which to choose!
|
||||
if ranked[0].1 == ranked[1].1 {
|
||||
let top = ranked[0];
|
||||
let second = ranked[0];
|
||||
if top.1 == second.1 {
|
||||
println!("Ambigous command '{}'.\nCould be any of {}, {}, etc...", text, top.0.name, second.0.name);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
@ -100,5 +93,57 @@ impl Command {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn commands() -> Vec<Self> {
|
||||
let path = Path::new("/bin");
|
||||
let res = fs::read_dir(path).expect("Failed to read /bin");
|
||||
|
||||
// load all the programs from /bin
|
||||
let bin = res.fold(Vec::new(), |mut v, contents| {
|
||||
if let Ok(cmd) = contents {
|
||||
if let Ok(t) = cmd.file_type() {
|
||||
if t.is_file() {
|
||||
// v.push(cmd.path());
|
||||
let cmd = Command::init(
|
||||
cmd.file_name().into_string().unwrap(),
|
||||
vec![],
|
||||
Box::new(move |args| {
|
||||
let name = cmd.path().to_str().unwrap().to_owned();
|
||||
let out = process::Command::new(name)
|
||||
.args(args)
|
||||
// FIXME not printing to out
|
||||
.stdout(Stdio::inherit())
|
||||
.output()
|
||||
.expect("Failed to call external program");
|
||||
let y = out.stdout.iter().map(|b| *b as char).collect::<String>();
|
||||
// TODO load into env
|
||||
// let status = out.status.code();
|
||||
println!("{y}");
|
||||
}
|
||||
)
|
||||
);
|
||||
v.push(cmd);
|
||||
}
|
||||
};
|
||||
} ;
|
||||
v
|
||||
});
|
||||
|
||||
// load custom programs
|
||||
let mut commands = vec![
|
||||
Command::init("exit", vec![], Box::new(|_| {
|
||||
std::process::exit(0);
|
||||
})),
|
||||
Command::init("custom_echo", vec![], Box::new(|f| {
|
||||
let f:Vec<&str>=f;
|
||||
let msg = &f[1..].iter().map(|s| s.to_owned()).intersperse(" ").collect::<String>();
|
||||
println!("{msg}");
|
||||
})),
|
||||
];
|
||||
|
||||
// combine with a move
|
||||
commands.extend(bin);
|
||||
commands
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user