info'
This commit is contained in:
parent
9cc1a64a91
commit
6de062e808
17
src/cmd/echo.rs
Normal file
17
src/cmd/echo.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use crate::command::Command;
|
||||||
|
|
||||||
|
pub fn init() -> Command {
|
||||||
|
Command::init(
|
||||||
|
"echo",
|
||||||
|
vec![],
|
||||||
|
Box::new(|args, _| {
|
||||||
|
let msg = &args[1..]
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_owned())
|
||||||
|
.intersperse(" ".to_string())
|
||||||
|
.collect::<String>();
|
||||||
|
println!("{msg}");
|
||||||
|
0
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
2
src/cmd/mod.rs
Normal file
2
src/cmd/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod echo;
|
||||||
|
pub mod random;
|
31
src/cmd/random.rs
Normal file
31
src/cmd/random.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use crate::command::Command;
|
||||||
|
|
||||||
|
pub fn init() -> Command {
|
||||||
|
Command::init(
|
||||||
|
"random",
|
||||||
|
vec![
|
||||||
|
Command::init(
|
||||||
|
"number",
|
||||||
|
vec![],
|
||||||
|
Box::new(|_, _| {
|
||||||
|
// how do you know it's not random?
|
||||||
|
println!("8");
|
||||||
|
0
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Command::init(
|
||||||
|
"string",
|
||||||
|
vec![],
|
||||||
|
Box::new(|_, _| {
|
||||||
|
// how do you know it's not random?
|
||||||
|
println!("hello world");
|
||||||
|
0
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Box::new(|args, env| {
|
||||||
|
println!("args: {:?} env: {:?}", args, env);
|
||||||
|
0
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
@ -8,11 +8,23 @@ use std::{
|
|||||||
use crate::SPECIAL_CHAR;
|
use crate::SPECIAL_CHAR;
|
||||||
|
|
||||||
type InnerEnv = HashMap<String, String>;
|
type InnerEnv = HashMap<String, String>;
|
||||||
pub struct Env {
|
pub struct CmdEnv {
|
||||||
inner: InnerEnv,
|
inner: InnerEnv,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Env {
|
impl std::fmt::Debug for CmdEnv {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let mut stu = f.debug_struct("CmdEnv");
|
||||||
|
|
||||||
|
for (k,v) in self.inner.iter() {
|
||||||
|
stu.field(k, v);
|
||||||
|
}
|
||||||
|
stu
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmdEnv {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: HashMap::new(),
|
inner: HashMap::new(),
|
||||||
@ -46,7 +58,8 @@ impl Env {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub type Args<'a, 'b> = &'b [String];
|
pub type Args<'a, 'b> = &'b [String];
|
||||||
trait Run = Fn(Args, &mut Env) -> i32;
|
// A function that takes args, the env, and returns a status code
|
||||||
|
trait Run = Fn(Args, &mut CmdEnv) -> i32;
|
||||||
type Cmd = Box<dyn Run>;
|
type Cmd = Box<dyn Run>;
|
||||||
|
|
||||||
pub struct Command {
|
pub struct Command {
|
||||||
@ -56,7 +69,7 @@ pub struct Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Command {
|
impl Command {
|
||||||
fn init<T>(name: T, sub_commands: Vec<Self>, f: Cmd) -> Self
|
pub fn init<T>(name: T, sub_commands: Vec<Self>, f: Cmd) -> Self
|
||||||
where
|
where
|
||||||
T: ToString,
|
T: ToString,
|
||||||
{
|
{
|
||||||
@ -67,7 +80,7 @@ impl Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(&self, words: Args, env: &mut Env) {
|
pub fn call(&self, words: Args, env: &mut CmdEnv) {
|
||||||
let x = &self.cmd;
|
let x = &self.cmd;
|
||||||
let exit_code = x(words, env);
|
let exit_code = x(words, env);
|
||||||
env.set("?", &exit_code.to_string());
|
env.set("?", &exit_code.to_string());
|
||||||
@ -110,7 +123,7 @@ impl Command {
|
|||||||
fn load_from(path: &str) -> Vec<Command> {
|
fn load_from(path: &str) -> Vec<Command> {
|
||||||
let path = Path::new(path);
|
let path = Path::new(path);
|
||||||
if let Ok(res) = fs::read_dir(path) {
|
if let Ok(res) = fs::read_dir(path) {
|
||||||
// load all the programs from /bin
|
// load all the programs from <path>
|
||||||
let bin = res.fold(Vec::new(), |mut v, contents| {
|
let bin = res.fold(Vec::new(), |mut v, contents| {
|
||||||
if let Ok(cmd) = contents {
|
if let Ok(cmd) = contents {
|
||||||
if let Ok(t) = cmd.file_type() {
|
if let Ok(t) = cmd.file_type() {
|
||||||
@ -119,10 +132,8 @@ impl Command {
|
|||||||
let cmd = Command::init(
|
let cmd = Command::init(
|
||||||
cmd.file_name().into_string().unwrap(),
|
cmd.file_name().into_string().unwrap(),
|
||||||
vec![],
|
vec![],
|
||||||
Box::new(move |args: Args, env: &mut Env| {
|
Box::new(move |args: Args, env: &mut CmdEnv| {
|
||||||
let name = cmd.path().to_str().unwrap().to_owned();
|
let name = cmd.path().to_str().unwrap().to_owned(); let out = process::Command::new(name) .args(&args[1..])
|
||||||
let out = process::Command::new(name)
|
|
||||||
.args(&args[1..])
|
|
||||||
.envs(env.as_env())
|
.envs(env.as_env())
|
||||||
.output()
|
.output()
|
||||||
.expect("Failed to call external program");
|
.expect("Failed to call external program");
|
||||||
@ -149,7 +160,7 @@ impl Command {
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_commands(env: &Env) -> Vec<Self> {
|
pub fn all_commands(env: &CmdEnv) -> Vec<Self> {
|
||||||
// load custom programs
|
// load custom programs
|
||||||
let mut commands = vec![
|
let mut commands = vec![
|
||||||
Command::init(
|
Command::init(
|
||||||
@ -159,46 +170,8 @@ impl Command {
|
|||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
Command::init(
|
crate::cmd::echo::init(),
|
||||||
"echo",
|
crate::cmd::random::init(),
|
||||||
vec![],
|
|
||||||
Box::new(|args, _| {
|
|
||||||
let msg = &args[1..]
|
|
||||||
.iter()
|
|
||||||
.map(|s| s.to_owned())
|
|
||||||
.intersperse(" ".to_string())
|
|
||||||
.collect::<String>();
|
|
||||||
println!("{msg}");
|
|
||||||
0
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
Command::init(
|
|
||||||
"random",
|
|
||||||
vec![
|
|
||||||
Command::init(
|
|
||||||
"number",
|
|
||||||
vec![],
|
|
||||||
Box::new(|_, _| {
|
|
||||||
// how do you know it's not random?
|
|
||||||
println!("8");
|
|
||||||
0
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
Command::init(
|
|
||||||
"string",
|
|
||||||
vec![],
|
|
||||||
Box::new(|_, _| {
|
|
||||||
// how do you know it's not random?
|
|
||||||
println!("hello world");
|
|
||||||
0
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
Box::new(|args, _| {
|
|
||||||
println!("random's debug: {:?}", args);
|
|
||||||
0
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// $PATH
|
// $PATH
|
||||||
|
12
src/main.rs
12
src/main.rs
@ -1,9 +1,10 @@
|
|||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
use std::io::{BufRead, Write};
|
use std::io::{BufRead, Write};
|
||||||
use command::{Command, Env, Args};
|
use command::{Command, CmdEnv, Args};
|
||||||
|
|
||||||
mod command;
|
mod command;
|
||||||
|
mod cmd;
|
||||||
|
|
||||||
pub static SPECIAL_CHAR: char = '$';
|
pub static SPECIAL_CHAR: char = '$';
|
||||||
|
|
||||||
@ -14,9 +15,10 @@ fn main() {
|
|||||||
let stdout = std::io::stdout();
|
let stdout = std::io::stdout();
|
||||||
let mut out_lock = stdout.lock();
|
let mut out_lock = stdout.lock();
|
||||||
|
|
||||||
let mut env= Env::new();
|
let mut env= CmdEnv::new();
|
||||||
env.set("HOME", "/a/fake/dir");
|
env.set("HOME", "/tmp/fake/dir");
|
||||||
env.set("?", "0");
|
env.set("?", "0");
|
||||||
|
// env.set("PATH", "/bin/");
|
||||||
|
|
||||||
let commands = &Command::all_commands(&env);
|
let commands = &Command::all_commands(&env);
|
||||||
println!("Loaded {} commands", commands.len());
|
println!("Loaded {} commands", commands.len());
|
||||||
@ -78,7 +80,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_lang(tokens: Args, env: &mut Env) {
|
fn parse_lang(tokens: Args, env: &mut CmdEnv) {
|
||||||
if let Some(first) = tokens.first() {
|
if let Some(first) = tokens.first() {
|
||||||
if let Some((var, val)) = first.split_once('=') {
|
if let Some((var, val)) = first.split_once('=') {
|
||||||
let var = var.replace(SPECIAL_CHAR, "");
|
let var = var.replace(SPECIAL_CHAR, "");
|
||||||
@ -100,7 +102,7 @@ fn parse_lang(tokens: Args, env: &mut Env) {
|
|||||||
};
|
};
|
||||||
env.set(&var, &val);
|
env.set(&var, &val);
|
||||||
} else {
|
} else {
|
||||||
println!("first token is not a command but also doesn't include '='");
|
println!("first token is not a command but also isn't setting a variable (=)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user