From c97f543cf2356e8cf420646f566fcfb3b29f07d4 Mon Sep 17 00:00:00 2001 From: stratact <stratact1@gmail.com> Date: Thu, 28 Jan 2016 07:32:20 -0800 Subject: [PATCH] Move rogue functions to methods and cleanup --- src/builtin.rs | 10 +- src/main.rs | 354 ++++++++++++++++++++++++------------------------- 2 files changed, 182 insertions(+), 182 deletions(-) diff --git a/src/builtin.rs b/src/builtin.rs index 0e1e2934..797a9ec5 100644 --- a/src/builtin.rs +++ b/src/builtin.rs @@ -2,7 +2,7 @@ use std::io::{stdout, Write}; use std::env; use std::process; -use super::{set_var, Variables}; +use super::{Shell, Variables}; use super::input_editor::readln; pub fn cd(args: &[String]) { @@ -16,7 +16,7 @@ pub fn cd(args: &[String]) { } } -pub fn read(args: &[String], variables: &mut Variables) { +pub fn read(args: &[String], shell: &mut Shell) { let mut out = stdout(); for i in 1..args.len() { if let Some(arg_original) = args.get(i) { @@ -27,13 +27,13 @@ pub fn read(args: &[String], variables: &mut Variables) { } if let Some(value_original) = readln() { let value = value_original.trim(); - set_var(variables, arg, value); + shell.set_var(arg, value); } } } } -pub fn run(args: &[String], variables: &mut Variables) { +pub fn run(args: &[String], shell: &mut Shell) { let path = "/apps/shell/main.bin"; let mut command = process::Command::new(path); @@ -48,7 +48,7 @@ pub fn run(args: &[String], variables: &mut Variables) { match child.wait() { Ok(status) => { if let Some(code) = status.code() { - set_var(variables, "?", &format!("{}", code)); + shell.set_var("?", &format!("{}", code)); } else { println!("{}: No child exit code", path); } diff --git a/src/main.rs b/src/main.rs index 5cb84a21..bce7745e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,10 +26,10 @@ pub type Variables = BTreeMap<String, String>; /// This struct will contain all of the data structures related to this /// instance of the shell. pub struct Shell { - pub variables: Variables, - pub modes: Vec<Mode>, - pub directory_stack: DirectoryStack, - pub history: VecDeque<String>, + variables: Variables, + modes: Vec<Mode>, + directory_stack: DirectoryStack, + history: VecDeque<String>, } impl Shell { @@ -42,6 +42,174 @@ impl Shell { history: VecDeque::new(), } } + + pub fn print_prompt(&self) { + let prompt_prefix = self.modes.iter().rev().fold(String::new(), |acc, mode| { + acc + + if mode.value { + "+ " + } else { + "- " + } + }); + print!("{}", prompt_prefix); + + let cwd = env::current_dir().ok().map_or("?".to_string(), + |ref p| p.to_str().unwrap_or("?").to_string()); + + print!("ion:{}# ", cwd); + if let Err(message) = stdout().flush() { + println!("{}: failed to flush prompt to stdout", message); + } + } + + fn on_command(&mut self, command_string: &str, commands: &HashMap<&str, Command>) { + let max_history: usize = 1000; // TODO temporary, make this configurable + if self.history.len() > max_history { + self.history.pop_front(); + } + self.history.push_back(command_string.to_string()); + + // Show variables + if command_string == "$" { + for (key, value) in self.variables.iter() { + println!("{}={}", key, value); + } + return; + } + + let mut jobs = parse(command_string); + expand_variables(&mut jobs, &self.variables); + + // Execute commands + for job in jobs.iter() { + if job.command == "if" { + let mut value = false; + + if let Some(left) = job.args.get(0) { + if let Some(cmp) = job.args.get(1) { + if let Some(right) = job.args.get(2) { + if cmp == "==" { + value = *left == *right; + } else if cmp == "!=" { + value = *left != *right; + } else if cmp == ">" { + value = left.to_num_signed() > right.to_num_signed(); + } else if cmp == ">=" { + value = left.to_num_signed() >= right.to_num_signed(); + } else if cmp == "<" { + value = left.to_num_signed() < right.to_num_signed(); + } else if cmp == "<=" { + value = left.to_num_signed() <= right.to_num_signed(); + } else { + println!("Unknown comparison: {}", cmp); + } + } else { + println!("No right hand side"); + } + } else { + println!("No comparison operator"); + } + } else { + println!("No left hand side"); + } + + self.modes.insert(0, Mode { value: value }); + continue; + } + + if job.command == "else" { + if let Some(mode) = self.modes.get_mut(0) { + mode.value = !mode.value; + } else { + println!("Syntax error: else found with no previous if"); + } + continue; + } + + if job.command == "fi" { + if !self.modes.is_empty() { + self.modes.remove(0); + } else { + println!("Syntax error: fi found with no previous if"); + } + continue; + } + + let mut skipped: bool = false; + for mode in self.modes.iter() { + if !mode.value { + skipped = true; + break; + } + } + if skipped { + continue; + } + + // Set variables + if let Some(i) = job.command.find('=') { + let name = job.command[0..i].trim(); + let mut value = job.command[i + 1..job.command.len()].trim().to_string(); + + for i in 0..job.args.len() { + if let Some(arg) = job.args.get(i) { + value = value + " " + &arg; + } + } + + self.set_var(name, &value); + continue; + } + + // Commands + let mut args = job.args.clone(); + args.insert(0, job.command.clone()); + if let Some(command) = commands.get(&job.command.as_str()) { + (*command.main)(&args, self); + } else { + self.run_external_commmand(args); + } + } + } + + fn run_external_commmand(&mut self, args: Vec<String>) { + if let Some(path) = args.get(0) { + let mut command = process::Command::new(path); + for i in 1..args.len() { + if let Some(arg) = args.get(i) { + command.arg(arg); + } + } + match command.spawn() { + Ok(mut child) => { + match child.wait() { + Ok(status) => { + if let Some(code) = status.code() { + self.set_var("?", &code.to_string()); + } else { + println!("{}: No child exit code", path); + } + } + Err(err) => println!("{}: Failed to wait: {}", path, err), + } + } + Err(err) => println!("{}: Failed to execute: {}", path, err), + } + } + } + + pub fn set_var(&mut self, name: &str, value: &str) { + if name.is_empty() { + return; + } + + if value.is_empty() { + self.variables.remove(&name.to_string()); + } else { + self.variables.insert(name.to_string(), value.to_string()); + } + } } /// Structure which represents a Terminal's command. @@ -99,7 +267,7 @@ impl Command { name: "read", help: "To read some variables\n read <my_variable>", main: box |args: &[String], shell: &mut Shell| { - builtin::read(args, &mut shell.variables); + builtin::read(args, shell); }, }); @@ -108,7 +276,7 @@ impl Command { name: "run", help: "Run a script\n run <script>", main: box |args: &[String], shell: &mut Shell| { - builtin::run(args, &mut shell.variables); + builtin::run(args, shell); }, }); @@ -182,174 +350,6 @@ pub struct Mode { value: bool, } -fn on_command(command_string: &str, commands: &HashMap<&str, Command>, shell: &mut Shell) { - let max_history: usize = 1000; // TODO temporary, make this configurable - if shell.history.len() > max_history { - shell.history.pop_front(); - } - shell.history.push_back(command_string.to_string()); - - // Show variables - if command_string == "$" { - for (key, value) in shell.variables.iter() { - println!("{}={}", key, value); - } - return; - } - - let mut jobs = parse(command_string); - expand_variables(&mut jobs, &shell.variables); - - // Execute commands - for job in jobs.iter() { - if job.command == "if" { - let mut value = false; - - if let Some(left) = job.args.get(0) { - if let Some(cmp) = job.args.get(1) { - if let Some(right) = job.args.get(2) { - if cmp == "==" { - value = *left == *right; - } else if cmp == "!=" { - value = *left != *right; - } else if cmp == ">" { - value = left.to_num_signed() > right.to_num_signed(); - } else if cmp == ">=" { - value = left.to_num_signed() >= right.to_num_signed(); - } else if cmp == "<" { - value = left.to_num_signed() < right.to_num_signed(); - } else if cmp == "<=" { - value = left.to_num_signed() <= right.to_num_signed(); - } else { - println!("Unknown comparison: {}", cmp); - } - } else { - println!("No right hand side"); - } - } else { - println!("No comparison operator"); - } - } else { - println!("No left hand side"); - } - - shell.modes.insert(0, Mode { value: value }); - continue; - } - - if job.command == "else" { - if let Some(mode) = shell.modes.get_mut(0) { - mode.value = !mode.value; - } else { - println!("Syntax error: else found with no previous if"); - } - continue; - } - - if job.command == "fi" { - if !shell.modes.is_empty() { - shell.modes.remove(0); - } else { - println!("Syntax error: fi found with no previous if"); - } - continue; - } - - let mut skipped: bool = false; - for mode in shell.modes.iter() { - if !mode.value { - skipped = true; - break; - } - } - if skipped { - continue; - } - - // Set variables - if let Some(i) = job.command.find('=') { - let name = job.command[0..i].trim(); - let mut value = job.command[i + 1..job.command.len()].trim().to_string(); - - for i in 0..job.args.len() { - if let Some(arg) = job.args.get(i) { - value = value + " " + &arg; - } - } - - set_var(&mut shell.variables, name, &value); - continue; - } - - // Commands - let mut args = job.args.clone(); - args.insert(0, job.command.clone()); - if let Some(command) = commands.get(&job.command.as_str()) { - (*command.main)(&args, shell); - } else { - run_external_commmand(args, &mut shell.variables); - } - } -} - - -pub fn set_var(variables: &mut Variables, name: &str, value: &str) { - if name.is_empty() { - return; - } - - if value.is_empty() { - variables.remove(&name.to_string()); - } else { - variables.insert(name.to_string(), value.to_string()); - } -} - -fn print_prompt(modes: &[Mode]) { - let prompt_prefix = modes.iter().rev().fold(String::new(), |acc, mode| { - acc + - if mode.value { - "+ " - } else { - "- " - } - }); - print!("{}", prompt_prefix); - - let cwd = env::current_dir().ok().map_or("?".to_string(), - |ref p| p.to_str().unwrap_or("?").to_string()); - - print!("ion:{}# ", cwd); - if let Err(message) = stdout().flush() { - println!("{}: failed to flush prompt to stdout", message); - } -} - -fn run_external_commmand(args: Vec<String>, variables: &mut Variables) { - if let Some(path) = args.get(0) { - let mut command = process::Command::new(path); - for i in 1..args.len() { - if let Some(arg) = args.get(i) { - command.arg(arg); - } - } - match command.spawn() { - Ok(mut child) => { - match child.wait() { - Ok(status) => { - if let Some(code) = status.code() { - set_var(variables, "?", &code.to_string()); - } else { - println!("{}: No child exit code", path); - } - } - Err(err) => println!("{}: Failed to wait: {}", path, err), - } - } - Err(err) => println!("{}: Failed to execute: {}", path, err), - } - } -} fn main() { let commands = Command::map(); @@ -362,20 +362,20 @@ fn main() { println!("{}: Failed to read {}", message, arg); } } - on_command(&command_list, &commands, &mut shell); + shell.on_command(&command_list, &commands); return; } loop { - print_prompt(&shell.modes); + shell.print_prompt(); if let Some(command_original) = readln() { let command = command_original.trim(); if command == "exit" { break; } else if !command.is_empty() { - on_command(&command, &commands, &mut shell); + shell.on_command(&command, &commands); } } else { break; -- GitLab