bash-like syntax
This commit is contained in:
parent
38b97f39b3
commit
e2df94a6c2
20
bash_info.md
Normal file
20
bash_info.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# invalid
|
||||||
|
```bash
|
||||||
|
$a="b"
|
||||||
|
a = "b"
|
||||||
|
a= "b"
|
||||||
|
a ="b"
|
||||||
|
```
|
||||||
|
|
||||||
|
# valid
|
||||||
|
```bash
|
||||||
|
a="b"
|
||||||
|
a=b
|
||||||
|
```
|
||||||
|
|
||||||
|
# examples
|
||||||
|
```bash
|
||||||
|
a="b c d"
|
||||||
|
echo $a
|
||||||
|
# output: b c d
|
||||||
|
```
|
@ -1,10 +1,12 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs::{self, ReadDir},
|
fs,
|
||||||
path::Path,
|
path::Path,
|
||||||
process,
|
process,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::SPECIAL_CHAR;
|
||||||
|
|
||||||
type InnerEnv = HashMap<String, String>;
|
type InnerEnv = HashMap<String, String>;
|
||||||
pub struct Env {
|
pub struct Env {
|
||||||
inner: InnerEnv,
|
inner: InnerEnv,
|
||||||
@ -30,7 +32,7 @@ impl Env {
|
|||||||
}
|
}
|
||||||
pub fn apply_args_substitution(&self, args: Args) -> Vec<String> {
|
pub fn apply_args_substitution(&self, args: Args) -> Vec<String> {
|
||||||
args.iter().fold(Vec::new(), |mut vec, arg| {
|
args.iter().fold(Vec::new(), |mut vec, arg| {
|
||||||
if arg.starts_with('$') {
|
if arg.starts_with(SPECIAL_CHAR) {
|
||||||
// we take a slice to get rid of the '$'
|
// we take a slice to get rid of the '$'
|
||||||
if let Some(sub) = self.get(&arg[1..]) {
|
if let Some(sub) = self.get(&arg[1..]) {
|
||||||
vec.push(sub.to_owned());
|
vec.push(sub.to_owned());
|
||||||
@ -66,9 +68,6 @@ impl Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(&self, words: Args, env: &mut Env) {
|
pub fn call(&self, words: Args, env: &mut Env) {
|
||||||
// apply env
|
|
||||||
let words: Args = &env.apply_args_substitution(words);
|
|
||||||
|
|
||||||
let x = &self.cmd;
|
let x = &self.cmd;
|
||||||
x(words, env)
|
x(words, env)
|
||||||
}
|
}
|
||||||
|
42
src/main.rs
42
src/main.rs
@ -5,6 +5,8 @@ use command::{Command, Env, Args};
|
|||||||
|
|
||||||
mod command;
|
mod command;
|
||||||
|
|
||||||
|
pub static SPECIAL_CHAR: char = '$';
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let stdin = std::io::stdin();
|
let stdin = std::io::stdin();
|
||||||
let mut in_lock = stdin.lock();
|
let mut in_lock = stdin.lock();
|
||||||
@ -14,7 +16,6 @@ fn main() {
|
|||||||
|
|
||||||
let mut env= Env::new();
|
let mut env= Env::new();
|
||||||
env.set("HOME", "/a/fake/dir");
|
env.set("HOME", "/a/fake/dir");
|
||||||
env.set("PS1", "> ");
|
|
||||||
|
|
||||||
let commands = &Command::all_commands(&env);
|
let commands = &Command::all_commands(&env);
|
||||||
println!("Loaded {} commands", commands.len());
|
println!("Loaded {} commands", commands.len());
|
||||||
@ -31,7 +32,10 @@ fn main() {
|
|||||||
.read_line(&mut buf)
|
.read_line(&mut buf)
|
||||||
.expect("Failed to read in to buffer.");
|
.expect("Failed to read in to buffer.");
|
||||||
|
|
||||||
let mut args: Args = &buf.trim().split(' ').map(|f| f.to_owned()).collect::<Vec<String>>();
|
// TODO split at ' ' but don't split when it's surrounded by quotes '"'
|
||||||
|
let args= &buf.trim().split(' ').map(|f| f.to_owned()).collect::<Vec<String>>();
|
||||||
|
let args = env.apply_args_substitution(args);
|
||||||
|
let mut args: Args = &args;
|
||||||
|
|
||||||
// let mut args: Args = &buf.trim().split(' ').collect::<Vec<&str>>();
|
// let mut args: Args = &buf.trim().split(' ').collect::<Vec<&str>>();
|
||||||
let mut options = commands;
|
let mut options = commands;
|
||||||
@ -44,7 +48,7 @@ fn main() {
|
|||||||
Some(choice) => {
|
Some(choice) => {
|
||||||
// No sub commands left to choose from, just pass the input
|
// No sub commands left to choose from, just pass the input
|
||||||
if choice.sub_commands.is_empty() {
|
if choice.sub_commands.is_empty() {
|
||||||
choice.call(args, &mut env);
|
choice.call(&args, &mut env);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,13 +59,14 @@ fn main() {
|
|||||||
if args.is_empty()
|
if args.is_empty()
|
||||||
|| Command::choose(&args[0], options).is_none() // yes, this means that we search for a choice twice if it misses, but the search takes all of 0ms, so it's fine.
|
|| Command::choose(&args[0], options).is_none() // yes, this means that we search for a choice twice if it misses, but the search takes all of 0ms, so it's fine.
|
||||||
{
|
{
|
||||||
choice.call(args, &mut env);
|
choice.call(&args, &mut env);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// When no good choice presents it's self
|
// When no good choice presents it's self
|
||||||
None => {
|
None => {
|
||||||
println!("No option...");
|
// perhaps they are trying to use builtins?
|
||||||
|
parse_lang(&args, &mut env);
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -71,3 +76,30 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_lang(tokens: Args, env: &mut Env) {
|
||||||
|
if let Some(first) = tokens.first() {
|
||||||
|
if let Some((var, val)) = first.split_once('=') {
|
||||||
|
let var = var.replace(SPECIAL_CHAR, "");
|
||||||
|
|
||||||
|
// Make it so that strings don't get spliced up
|
||||||
|
let val = if val.starts_with('"') {
|
||||||
|
let mut buf = String::new();
|
||||||
|
buf += &val;
|
||||||
|
for i in &tokens[1..] {
|
||||||
|
buf += " ";
|
||||||
|
buf += i;
|
||||||
|
if i.ends_with('"') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.replace('"', "")
|
||||||
|
} else {
|
||||||
|
val.to_owned()
|
||||||
|
};
|
||||||
|
env.set(&var, &val);
|
||||||
|
} else {
|
||||||
|
println!("first token is not a command but also doesn't include '='");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user