diff --git a/README.md b/README.md index e91b0d8..0c62d1e 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,13 @@ Sqish is now my default shell on my home computer, and I'll keep adding features Also keep in mind I'm a beginner in Rust, so the code is pretty dirty; I will probably come around to reformating it once I have all the features I want and ironed out all the bugs. -TODO: +# TODO + +TODO (Reformat): +* Creating a struct "shell" that contains builder method taking an input and an output as parameters as well as a conf could be cool +* Maybe subdivide lib.src to have more modularity 'cause it getting kinda long... 500 lines it a bit much ? + +TODO(Features): * Allow redirecting >> to the end of a file ? * Allow && in commands ? * Improve word jumping diff --git a/src/lib.rs b/src/lib.rs index 92c4fb5..82c579e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ pub mod shell { use termion::input::TermRead; use termion::raw::IntoRawMode; use termion::raw::RawTerminal; - use termion::cursor; + use termion::{color, cursor}; use termion; use unicode_segmentation::UnicodeSegmentation; use std::collections::HashMap; @@ -33,7 +33,46 @@ pub mod shell { extern crate shell_words; extern crate ctrlc; - fn change_dir(args: &Vec, previous_command: &mut Option) { + ///Stores essential terminal variables + struct TermElements { + //Stores currently typed command + command: String, + //Current cursor position in the line + cur_pos: usize, + //Max position of cursor in the line + max_pos: usize, + stdout: RawTerminal, + //Current history number + current_number: i32, + //Configuration + conf: SqishConf, + } + + ///Used to unify command output and error handling + ///across functions + struct CmdOutput { + outp: String, + rc: i16, + } + + impl CmdOutput { + fn from_values(output: String, rc: i16) -> CmdOutput { + let myoutp = CmdOutput { + outp: output, + rc: rc, + }; + return myoutp; + } + fn new_empty() -> CmdOutput { + let outp = CmdOutput { + outp: String::new(), + rc: 0, + }; + return outp; + } + } + + fn change_dir(args: &Vec, previous_command: &mut Option) -> Result { let homedir = dirs::home_dir().unwrap().into_os_string().into_string().unwrap(); //let new_dir = args.peekable().peek().map_or(homedir.as_str(), |x| *x); let mut new_dir = String::new(); @@ -45,14 +84,15 @@ pub mod shell { let root = Path::new(&new_dir); if let Err(e) = env::set_current_dir(&root) { - eprintln!(" Err: {}", e); - } else { - println!(""); - } + return Err(CmdOutput::from_values( + format!("Error setting directory to {}, got {:?}", + new_dir, e), -1)); + }; *previous_command = None; + return Ok(CmdOutput::new_empty()); } - fn print_hist(previous_command: &mut Option, command_next: bool) { + fn print_hist(previous_command: &mut Option, command_next: bool) -> Result { //let stdout = Stdio::inherit(); let res = get_history(); match res { @@ -65,31 +105,19 @@ pub mod shell { print!("{}", r); } }, - Err(e) => eprintln!(" Err reading history: {}", e), + Err(e) => { + return Err(CmdOutput::from_values(format!("Could not print history, got {:?}", e), 255)); + }, } + return Ok(CmdOutput::new_empty()); } - struct CmdOutput { - outp: String, - rc: i16, - } - - impl CmdOutput { - fn from_values(output: String, rc: i16) -> CmdOutput { - let myoutp = CmdOutput { - outp: output, - rc: rc, - } - return myoutp; - } - } fn process_line(input: &str) -> Result { let mut commands = input.trim().split("|").peekable(); let mut previous_command = None; let mut resultat = String::new(); - - let mut outp = CmdOutput::new_empty(); + let mut rc: i16 = 0; while let Some(command) = commands.next() { let parts = match shell_words::split(&command.trim()) { @@ -103,11 +131,11 @@ pub mod shell { match command { "cd" => { - change_dir(&args, &mut previous_command); + change_dir(&args, &mut previous_command)?; }, "history" => { let next = commands.peek().is_some(); - print_hist(&mut previous_command, next); + print_hist(&mut previous_command, next)?; }, command => { if commands.peek().is_some() { @@ -145,7 +173,7 @@ pub mod shell { Ok(h) => h, Err(_) => { let err_string = format!("Not found : {}", command); - return String::from(err_string); + return Err(CmdOutput::from_values(err_string, -1)); }, }; @@ -159,12 +187,15 @@ pub mod shell { previous_command = None; let format_res = format!("{}", status); - let _ = &mut resultat.push_str(&format_res); + *&mut rc = format_res.parse::().unwrap(); + *&mut resultat = String::from_utf8(output.stdout).unwrap(); + //let _ = &mut resultat.push_str(&format_res); } }, }; } - return resultat; + //return resultat; + return Ok(CmdOutput::from_values(resultat, rc)); } fn replace_signs(line: &String) -> String { @@ -184,17 +215,18 @@ pub mod shell { return ayo; } - fn handle_input(line: &str) -> String { + fn handle_input(line: &str) -> Result { //history callback if (line.len() > 0) && (line.starts_with('!')) { let command_found = treat_history_callback(line); match command_found { Some(c) => { write_to_history(&c); - let outp = process_line(&c); - return outp; + return process_line(&c); }, - None => return String::from(" "), + None => return Err(CmdOutput::from_values( + String::from("No such value"), + 255)), }; //Regular command } else if line.len() > 0 { @@ -203,7 +235,7 @@ pub mod shell { //Nothing } else { //Command was empty, new line - return String::from(""); + return Ok(CmdOutput::new_empty()); } } @@ -281,25 +313,36 @@ pub mod shell { current_number: &mut i32, conf: &mut SqishConf, stdout: &mut RawTerminal) { + //NORMAL CMD if (mycommand != &String::from("")) && (mycommand != &String::from("exit")) { + //Run the command let comm = replace_signs(&mycommand); RawTerminal::suspend_raw_mode(&stdout); let res = handle_input(&comm); + //Display the results + match res { + Ok(_) => (), + Err(e) => { + println!("\r\n{}Got error {}, RC : {:?}{}", + color::Fg(color::Red), + e.outp, + e.rc, + color::Fg(color::Reset)); + }, + }; + //Prepare for a new command RawTerminal::activate_raw_mode(&stdout); mycommand.clear(); - for line in res.split("\r\n") { - if line != "" && line.starts_with('N'){ - write!(stdout, "{}\r\n", line); - } - } conf.update_prompt(get_curr_history_number()); write!(stdout, "{}", conf.promptline).unwrap(); stdout.flush(); *current_number += 1; + //EXITTING } else if mycommand == &String::from("exit") { write!(stdout, "\r\nThanks for using Sqish!\r\nSayonara \r\n"); RawTerminal::suspend_raw_mode(&stdout); std::process::exit(0); + //EMPTY LINE } else { conf.update_prompt(get_curr_history_number()); write!(stdout, "\r\n{}", conf.promptline).unwrap(); @@ -535,20 +578,6 @@ pub mod shell { write!(elems.stdout, "{}{}", elems.conf.promptline, elems.command); } - struct TermElements { - //Stores currently typed command - command: String, - //Current cursor position in the line - cur_pos: usize, - //Max position of cursor in the line - max_pos: usize, - stdout: RawTerminal, - //Current history number - current_number: i32, - //Configuration - conf: SqishConf, - } - fn jmp_nxt_word(elems: &mut TermElements) { let steps = find_next_space(&elems.cur_pos, &elems.max_pos, &elems.command); //println!("steps: {:?} cur {:?} max {:?}", steps, elems.cur_pos, elems.max_pos);