From 06ce1ffe2567eda8291596f78042963c34cf21ec Mon Sep 17 00:00:00 2001 From: fdai7451 Date: Sat, 21 Jan 2023 16:51:27 +0100 Subject: [PATCH] feat: add command to change prompt style --- src/builtins/cd.rs | 17 +++++++++++++---- src/builtins/change_prompt.rs | 30 ++++++++++++++++++++++++++++++ src/builtins/exit.rs | 4 ++-- src/builtins/mod.rs | 34 +++++++++++++++++++++++++++++----- src/execute.rs | 10 +++++++--- src/main.rs | 6 ++++-- src/prompt.rs | 1 + 7 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 src/builtins/change_prompt.rs diff --git a/src/builtins/cd.rs b/src/builtins/cd.rs index 6127a27..5b03ffe 100644 --- a/src/builtins/cd.rs +++ b/src/builtins/cd.rs @@ -1,4 +1,4 @@ -use crate::builtins::Builtin; +use crate::builtins::{Builtin, BuiltinConfig}; use std::env::set_current_dir; use crate::error::ShellError; @@ -6,7 +6,7 @@ use crate::error::ShellError; pub struct Cd; impl Builtin for Cd { - fn execute(&mut self, args: Vec) -> Result<(), ShellError> { + fn execute(&mut self, _: &mut BuiltinConfig, args: Vec) -> Result<(), ShellError> { let Some(first) = args.get(0) else { return Err(ShellError::ExecuteFailure("no argument given".to_string())) }; @@ -22,7 +22,10 @@ mod tests { #[test] fn test_cd_current() { - assert_eq!(Cd.execute(vec![".".to_string()]), Ok(())) + assert_eq!( + Cd.execute(&mut BuiltinConfig::new(), vec![".".to_string()]), + Ok(()) + ) } #[test] @@ -37,6 +40,12 @@ mod tests { } // No such file or directory (os error 2) - assert_ne!(Cd.execute(vec![path.to_string_lossy().to_string()]), Ok(())) + assert_ne!( + Cd.execute( + &mut BuiltinConfig::new(), + vec![path.to_string_lossy().to_string()] + ), + Ok(()) + ) } } diff --git a/src/builtins/change_prompt.rs b/src/builtins/change_prompt.rs new file mode 100644 index 0000000..014355a --- /dev/null +++ b/src/builtins/change_prompt.rs @@ -0,0 +1,30 @@ +use crate::builtins::{Builtin, BuiltinConfig}; +use crate::error::ShellError; +use crate::prompt::PromptStyle; + +pub struct ChangePrompt; + +impl Builtin for ChangePrompt { + fn execute(&mut self, config: &mut BuiltinConfig, args: Vec) -> Result<(), ShellError> { + if args.len() > 1 { + Err(ShellError::ExecuteFailure( + "expected only one argument".to_string(), + )) + } else if let Some(style) = args.get(0) { + match style.to_lowercase().as_str() { + "none" => config.prompt_style = PromptStyle::None, + _ => { + return Err(ShellError::ExecuteFailure(format!( + "{} is not a valid prompt style", + style + ))) + } + } + Ok(()) + } else { + Err(ShellError::ExecuteFailure( + "expected at least one argument".to_string(), + )) + } + } +} diff --git a/src/builtins/exit.rs b/src/builtins/exit.rs index a9bfc20..96f7429 100644 --- a/src/builtins/exit.rs +++ b/src/builtins/exit.rs @@ -1,10 +1,10 @@ -use crate::builtins::Builtin; +use crate::builtins::{Builtin, BuiltinConfig}; use crate::error::ShellError; pub struct Exit; impl Builtin for Exit { - fn execute(&mut self, _: Vec) -> Result<(), ShellError> { + fn execute(&mut self, _: &mut BuiltinConfig, _: Vec) -> Result<(), ShellError> { std::process::exit(0) } } diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index c851029..b091e95 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -1,26 +1,50 @@ use crate::error::ShellError; +use crate::prompt::PromptStyle; use once_cell::unsync::Lazy; + mod cd; +mod change_prompt; mod exit; +pub struct BuiltinConfig { + pub prompt_style: PromptStyle, +} + +impl BuiltinConfig { + pub fn new() -> Self { + Self { + prompt_style: PromptStyle::None, + } + } +} + trait Builtin: Sync + Send { - fn execute(&mut self, args: Vec) -> Result<(), ShellError>; + fn execute(&mut self, config: &mut BuiltinConfig, args: Vec) -> Result<(), ShellError>; } -const BUILTINS: Lazy)>> = - Lazy::new(|| vec![("cd", Box::new(cd::Cd)), ("exit", Box::new(exit::Exit))]); +const BUILTINS: Lazy)>> = Lazy::new(|| { + vec![ + ("cd", Box::new(cd::Cd)), + ("change-prompt", Box::new(change_prompt::ChangePrompt)), + ("exit", Box::new(exit::Exit)), + ] +}); pub fn is_builtin(keyword: &str) -> bool { BUILTINS.iter().find(|(k, _)| k == &keyword).is_some() } #[allow(const_item_mutation)] -pub fn execute_builtin(keyword: &str, args: Vec) -> Result<(), ShellError> { +pub fn execute_builtin( + keyword: &str, + config: &mut BuiltinConfig, + args: Vec, +) -> Result<(), ShellError> { if let Some(builtin) = BUILTINS .iter_mut() .find_map(|(k, c)| if k == &keyword { Some(c) } else { None }) { - builtin.execute(args)? + builtin.execute(config, args)? } Ok(()) } diff --git a/src/execute.rs b/src/execute.rs index 7a2f18d..fd3de28 100644 --- a/src/execute.rs +++ b/src/execute.rs @@ -3,18 +3,22 @@ use std::io::ErrorKind; use std::process::{Command, ExitStatus}; use std::{io, thread}; -use crate::builtins::{execute_builtin, is_builtin}; +use crate::builtins::{execute_builtin, is_builtin, BuiltinConfig}; use crate::error::ShellError; use crate::parse::parse_line; -pub fn interpret(line: String, ctrlc_recv: Receiver<()>) -> Result<(), ShellError> { +pub fn interpret( + line: String, + config: &mut BuiltinConfig, + ctrlc_recv: Receiver<()>, +) -> Result<(), ShellError> { if line.is_empty() { return Err(ShellError::EmptyLine); } let (keyword, args) = parse_line(&line)?; if is_builtin(keyword) { - execute_builtin(keyword, args)?; + execute_builtin(keyword, config, args)?; } else { let mut command = Command::new(keyword); command.args(args); diff --git a/src/main.rs b/src/main.rs index 332e744..d20e788 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod execute; mod parse; mod prompt; +use crate::builtins::BuiltinConfig; use crate::error::ShellError; use execute::interpret; use rustyline::config::Configurer; @@ -22,13 +23,14 @@ fn main() -> Result<()> { rl.set_auto_add_history(true); let mut prompt = Prompt::new(); + let mut config = BuiltinConfig::new(); loop { let readline = rl.readline(&prompt.get_prompt()); match readline { - Ok(line) => match interpret(line, ctrlc_recv.clone()) { - Ok(_) => {} + Ok(line) => match interpret(line, &mut config, ctrlc_recv.clone()) { + Ok(_) => prompt.style = config.prompt_style.clone(), Err(ShellError::EmptyLine) => { continue; } diff --git a/src/prompt.rs b/src/prompt.rs index e3216bf..9b6a0be 100644 --- a/src/prompt.rs +++ b/src/prompt.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; +#[derive(Clone)] pub enum PromptStyle { None, }