1mod cd;
8mod colon;
9mod command;
10mod echo;
11mod eval;
12mod exit;
13mod export;
14mod print;
15mod read_builtin;
16mod readonly;
17mod return_builtin;
18mod set;
19mod setopt;
20mod stubs;
21mod test_builtin;
22mod true_false;
23mod typeset;
24mod unset;
25mod whence;
26
27use std::collections::HashMap;
28
29pub trait ShellEnvironment {
36 fn get_var(&self, name: &str) -> Option<&str>;
37 fn set_var(&mut self, name: &str, value: &str);
38 fn export_var(&mut self, name: &str);
39 fn unset_var(&mut self, name: &str);
40 fn exit_status(&self) -> i32;
41 fn set_exit_status(&mut self, status: i32);
42 fn chdir(&mut self, path: &str) -> Result<(), String>;
43 fn home_dir(&self) -> Option<&str>;
44}
45
46pub trait Builtin: Send + Sync {
50 fn name(&self) -> &str;
52
53 fn execute(&self, args: &[&str], env: &mut dyn ShellEnvironment) -> i32;
57}
58
59pub struct BuiltinRegistry {
63 builtins: HashMap<String, Box<dyn Builtin>>,
64}
65
66impl BuiltinRegistry {
67 pub fn new() -> Self {
69 Self {
70 builtins: HashMap::new(),
71 }
72 }
73
74 pub fn register(&mut self, builtin: Box<dyn Builtin>) {
76 self.builtins.insert(builtin.name().to_owned(), builtin);
77 }
78
79 pub fn get(&self, name: &str) -> Option<&dyn Builtin> {
81 self.builtins.get(name).map(|b| b.as_ref())
82 }
83
84 pub fn contains(&self, name: &str) -> bool {
86 self.builtins.contains_key(name)
87 }
88
89 pub fn iter(&self) -> impl Iterator<Item = &dyn Builtin> {
91 self.builtins.values().map(|b| b.as_ref())
92 }
93}
94
95impl Default for BuiltinRegistry {
96 fn default() -> Self {
97 Self::new()
98 }
99}
100
101pub fn default_builtins() -> BuiltinRegistry {
105 let mut reg = BuiltinRegistry::new();
106 reg.register(Box::new(cd::Cd));
107 reg.register(Box::new(colon::Colon));
108 reg.register(Box::new(command::CommandBuiltin));
109 reg.register(Box::new(echo::Echo));
110 reg.register(Box::new(eval::Eval));
111 reg.register(Box::new(exit::Exit));
112 reg.register(Box::new(export::Export));
113 reg.register(Box::new(print::Print));
114 reg.register(Box::new(read_builtin::ReadBuiltin));
115 reg.register(Box::new(return_builtin::Return));
116 reg.register(Box::new(set::Set));
117 reg.register(Box::new(set::Shift));
118 reg.register(Box::new(test_builtin::Test));
119 reg.register(Box::new(test_builtin::TestKeyword));
120 reg.register(Box::new(true_false::True));
121 reg.register(Box::new(true_false::False));
122 reg.register(Box::new(typeset::Typeset));
123 reg.register(Box::new(typeset::Local));
124 reg.register(Box::new(typeset::Declare));
125 reg.register(Box::new(unset::Unset));
126 reg.register(Box::new(whence::Whence));
127 reg.register(Box::new(whence::Which));
128 reg.register(Box::new(setopt::Setopt));
129 reg.register(Box::new(setopt::Unsetopt));
130 reg.register(Box::new(readonly::Readonly));
131 reg.register(Box::new(stubs::Autoload));
133 reg.register(Box::new(stubs::Zmodload));
134 reg.register(Box::new(stubs::Integer));
135 reg.register(Box::new(stubs::Float));
136 reg.register(Box::new(stubs::Let));
137 reg.register(Box::new(stubs::Trap));
138 reg.register(Box::new(stubs::Hash));
139 reg.register(Box::new(stubs::Disable));
140 reg.register(Box::new(stubs::Enable));
141 reg.register(Box::new(stubs::Emulate));
142 reg.register(Box::new(stubs::Zle));
143 reg.register(Box::new(stubs::Bindkey));
144 reg.register(Box::new(stubs::Compdef));
145 reg.register(Box::new(stubs::Zstyle));
146 reg.register(Box::new(stubs::Alias));
147 reg.register(Box::new(stubs::Unalias));
148 reg.register(Box::new(stubs::BuiltinCmd));
149 reg.register(Box::new(stubs::Wait));
150 reg.register(Box::new(stubs::Fg));
151 reg.register(Box::new(stubs::Bg));
152 reg.register(Box::new(stubs::Jobs));
153 reg.register(Box::new(stubs::Suspend));
154 reg.register(Box::new(stubs::Times));
155 reg.register(Box::new(stubs::Umask));
156 reg.register(Box::new(stubs::Ulimit));
157 reg.register(Box::new(stubs::Getopts));
158 reg.register(Box::new(stubs::Pushd));
159 reg.register(Box::new(stubs::Popd));
160 reg.register(Box::new(stubs::Dirs));
161 reg.register(Box::new(stubs::Limit));
162 reg.register(Box::new(stubs::Unlimit));
163 reg.register(Box::new(stubs::Sched));
164 reg.register(Box::new(stubs::Rehash));
165 reg.register(Box::new(stubs::Noglob));
166 reg
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172
173 #[test]
174 fn default_registry_contains_expected_builtins() {
175 let reg = default_builtins();
176 assert!(reg.contains("cd"));
177 assert!(reg.contains(":"));
178 assert!(reg.contains("command"));
179 assert!(reg.contains("echo"));
180 assert!(reg.contains("eval"));
181 assert!(reg.contains("exit"));
182 assert!(reg.contains("export"));
183 assert!(reg.contains("print"));
184 assert!(reg.contains("read"));
185 assert!(reg.contains("return"));
186 assert!(reg.contains("set"));
187 assert!(reg.contains("shift"));
188 assert!(reg.contains("["));
189 assert!(reg.contains("test"));
190 assert!(reg.contains("true"));
191 assert!(reg.contains("false"));
192 assert!(reg.contains("typeset"));
193 assert!(reg.contains("local"));
194 assert!(reg.contains("declare"));
195 assert!(reg.contains("unset"));
196 assert!(reg.contains("whence"));
197 assert!(reg.contains("which"));
198 assert!(!reg.contains("nonexistent"));
199 }
200}