use crate::error::ShellError; use crate::prompt::PromptStyle; use once_cell::unsync::Lazy; mod cd; mod change_prompt; mod exit; mod pwd; pub struct BuiltinConfig { pub prompt_style: PromptStyle, } impl BuiltinConfig { pub fn new() -> Self { Self { prompt_style: PromptStyle::Default, } } } trait Builtin: Sync + Send { fn execute(&mut self, config: &mut BuiltinConfig, args: Vec) -> Result<(), ShellError>; } const BUILTINS: Lazy)>> = Lazy::new(|| { vec![ ("cd", Box::new(cd::Cd)), ("change-prompt", Box::new(change_prompt::ChangePrompt)), ("exit", Box::new(exit::Exit)), ("pwd", Box::new(pwd::Pwd)), ] }); 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, 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(config, args)? } Ok(()) } #[cfg(test)] mod tests { use super::*; #[test] fn test_is_builtin_exit() { assert_eq!(is_builtin("exit"), true); } #[test] fn test_is_builtin_cd() { assert_eq!(is_builtin("cd"), true); } #[test] fn test_is_builtin_pwd() { assert_eq!(is_builtin("pwd"), true); } #[test] fn test_is_builtin_change_prompt() { assert_eq!(is_builtin("change-prompt"), true); } #[test] fn test_is_builtin_notabuiltin() { assert_eq!(is_builtin("notabuiltin"), false) } }