1use std::collections::HashMap;
4use std::path::PathBuf;
5
6pub use shell_builder::State as ShellBuilderState;
7
8use super::Shell;
9use crate::shell::KeyBindingsHelper;
10use crate::{
11 ProfileLoadBehavior, RcLoadBehavior, ShellFd, ShellVariable, builtins, callstack, completion,
12 env, error, extensions, functions, jobs, openfiles, options, pathcache, traps,
13};
14
15impl<SE: extensions::ShellExtensions, S: shell_builder::IsComplete> ShellBuilder<SE, S> {
16 pub async fn build(self) -> Result<Shell<SE>, error::Error> {
19 let mut options = self.build_settings();
20
21 let profile = std::mem::take(&mut options.profile);
22 let rc = std::mem::take(&mut options.rc);
23
24 let mut shell = Shell::new(options)?;
26
27 if !profile.skip() || !rc.skip() {
31 shell.load_config(&profile, &rc).await?;
32 }
33
34 Ok(shell)
35 }
36}
37
38impl<SE: extensions::ShellExtensions, S: shell_builder::State> ShellBuilder<SE, S> {
39 pub fn disable_option(mut self, option: impl Into<String>) -> Self {
41 self.disabled_options.push(option.into());
42 self
43 }
44
45 pub fn enable_option(mut self, option: impl Into<String>) -> Self {
47 self.enabled_options.push(option.into());
48 self
49 }
50
51 pub fn disable_options(mut self, options: impl IntoIterator<Item: Into<String>>) -> Self {
53 self.disabled_options
54 .extend(options.into_iter().map(Into::into));
55 self
56 }
57
58 pub fn enable_options(mut self, options: impl IntoIterator<Item: Into<String>>) -> Self {
60 self.enabled_options
61 .extend(options.into_iter().map(Into::into));
62 self
63 }
64
65 pub fn disable_shopt_option(mut self, option: impl Into<String>) -> Self {
67 self.disabled_shopt_options.push(option.into());
68 self
69 }
70
71 pub fn enable_shopt_option(mut self, option: impl Into<String>) -> Self {
73 self.enabled_shopt_options.push(option.into());
74 self
75 }
76
77 pub fn disable_shopt_options(mut self, options: impl IntoIterator<Item: Into<String>>) -> Self {
79 self.disabled_shopt_options
80 .extend(options.into_iter().map(Into::into));
81 self
82 }
83
84 pub fn enable_shopt_options(mut self, options: impl IntoIterator<Item: Into<String>>) -> Self {
86 self.enabled_shopt_options
87 .extend(options.into_iter().map(Into::into));
88 self
89 }
90
91 pub fn builtin(mut self, name: impl Into<String>, reg: builtins::Registration<SE>) -> Self {
93 self.builtins.insert(name.into(), reg);
94 self
95 }
96
97 pub fn builtins(
99 mut self,
100 builtins: impl IntoIterator<Item = (String, builtins::Registration<SE>)>,
101 ) -> Self {
102 self.builtins.extend(builtins);
103 self
104 }
105
106 pub fn var(mut self, name: impl Into<String>, variable: ShellVariable) -> Self {
108 self.vars.insert(name.into(), variable);
109 self
110 }
111}
112
113#[derive(Default, bon::Builder)]
115#[builder(
116 builder_type(
117 name = ShellBuilder,
118 doc {
119 }),
121 finish_fn(
122 name = build_settings,
123 vis = "pub(self)",
124 ),
125 start_fn(
126 vis = "pub(self)"
127 )
128)]
129pub struct CreateOptions<SE: extensions::ShellExtensions = extensions::DefaultShellExtensions> {
130 #[builder(field)]
132 pub disabled_options: Vec<String>,
133 #[builder(field)]
135 pub enabled_options: Vec<String>,
136 #[builder(field)]
138 pub disabled_shopt_options: Vec<String>,
139 #[builder(field)]
141 pub enabled_shopt_options: Vec<String>,
142 #[builder(field)]
144 pub builtins: HashMap<String, builtins::Registration<SE>>,
145 #[builder(field)]
149 pub vars: HashMap<String, ShellVariable>,
150 #[builder(default)]
152 pub error_formatter: SE::ErrorFormatter,
153 #[builder(default)]
155 pub disallow_overwriting_regular_files_via_output_redirection: bool,
156 #[builder(default)]
158 pub do_not_execute_commands: bool,
159 #[builder(default)]
161 pub exit_after_one_command: bool,
162 #[builder(default)]
164 pub interactive: bool,
165 #[builder(default)]
167 pub login: bool,
168 #[builder(default)]
170 pub no_editing: bool,
171 #[builder(default)]
173 pub profile: ProfileLoadBehavior,
174 #[builder(default)]
176 pub rc: RcLoadBehavior,
177 #[builder(default)]
180 pub do_not_inherit_env: bool,
181 #[builder(default)]
183 pub skip_well_known_vars: bool,
184 #[builder(default)]
186 pub fds: HashMap<ShellFd, openfiles::OpenFile>,
187 #[builder(default)]
189 pub external_cmd_leads_session: bool,
190 #[builder(default)]
195 pub kill_external_commands_on_drop: bool,
196 pub working_dir: Option<PathBuf>,
199 #[builder(default)]
201 pub posix: bool,
202 #[builder(default)]
204 pub print_commands_and_arguments: bool,
205 #[builder(default)]
207 pub read_commands_from_stdin: bool,
208 pub shell_name: Option<String>,
210 pub shell_args: Option<Vec<String>>,
212 pub shell_product_display_str: Option<String>,
215 #[builder(default)]
217 pub sh_mode: bool,
218 #[builder(default)]
220 pub treat_unset_variables_as_error: bool,
221 #[builder(default)]
223 pub exit_on_nonzero_command_exit: bool,
224 #[builder(default)]
226 pub disable_pathname_expansion: bool,
227 #[builder(default)]
229 pub verbose: bool,
230 #[builder(default)]
232 pub parser: crate::parser::ParserImpl,
233 #[builder(default)]
235 pub command_string_mode: bool,
236 pub max_function_call_depth: Option<usize>,
238 pub key_bindings: Option<KeyBindingsHelper>,
240 pub shell_version: Option<String>,
242}
243
244impl<SE: extensions::ShellExtensions> Default for Shell<SE> {
245 fn default() -> Self {
246 Self {
247 error_formatter: SE::ErrorFormatter::default(),
248 traps: traps::TrapHandlerConfig::default(),
249 open_files: openfiles::OpenFiles::default(),
250 working_dir: PathBuf::default(),
251 env: env::ShellEnvironment::default(),
252 funcs: functions::FunctionEnv::default(),
253 options: options::RuntimeOptions::default(),
254 jobs: jobs::JobManager::default(),
255 aliases: HashMap::default(),
256 last_exit_status: 0,
257 last_exit_status_change_count: 0,
258 last_pipeline_statuses: vec![0],
259 depth: 0,
260 name: None,
261 args: vec![],
262 version: None,
263 product_display_str: None,
264 call_stack: callstack::CallStack::new(),
265 directory_stack: vec![],
266 completion: completion::State::default(),
267 builtins: HashMap::default(),
268 program_location_cache: pathcache::PathCache::default(),
269 last_stopwatch_time: std::time::SystemTime::now(),
270 last_stopwatch_offset: 0,
271 parser_impl: crate::parser::ParserImpl::default(),
272 key_bindings: None,
273 history: None,
274 }
275 }
276}
277
278impl Shell {
279 pub fn builder() -> ShellBuilder<extensions::DefaultShellExtensions, shell_builder::Empty> {
281 CreateOptions::builder()
282 }
283
284 pub fn builder_with_extensions<SE: extensions::ShellExtensions>()
287 -> ShellBuilder<SE, shell_builder::Empty> {
288 CreateOptions::builder()
289 }
290}