bash-like syntax
This commit is contained in:
		
							
								
								
									
										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 '='");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user