1use self::args::{Run, Source, Work};
20use std::str::FromStr as _;
21use yash_env::Env;
22use yash_env::input::IgnoreEofConfig;
23use yash_env::input::SuspendedJobsGuardConfig;
24use yash_env::io::Fd;
25use yash_env::option::Option::{Interactive, Monitor, Stdin};
26use yash_env::option::State::On;
27use yash_env::parser::IsKeyword;
28use yash_env::parser::IsName;
29use yash_env::prompt::GetPrompt;
30use yash_env::semantics::command::RunFunction;
31use yash_env::system::resource::GetRlimit;
32use yash_env::system::{Chdir, GetCwd, GetUid, Isatty, Sysconf, TcGetPgrp, Times, Umask, Write};
33use yash_env::trap::RunSignalTrapIfCaught;
34use yash_prompt::ExpandText;
35use yash_semantics::expansion::expand_text;
36use yash_semantics::{RunReadEvalLoop, Runtime};
37use yash_syntax::parser::lex::Lexer;
38
39pub mod args;
40pub mod init_file;
41pub mod input;
42
43pub fn auto_interactive<S: Isatty>(system: &S, run: &Run) -> bool {
52 if run.work.source != Source::Stdin {
53 return false;
54 }
55 if run.options.iter().any(|&(o, _)| o == Interactive) {
56 return false;
57 }
58 system.isatty(Fd::STDIN) && system.isatty(Fd::STDERR)
59}
60
61pub async fn configure_environment<S>(env: &mut Env<S>, run: Run) -> Work
71where
72 S: Chdir
73 + Clone
74 + GetCwd
75 + GetRlimit
76 + GetUid
77 + Runtime
78 + Sysconf
79 + TcGetPgrp
80 + Times
81 + Umask
82 + Write
83 + 'static,
84{
85 if auto_interactive(&env.system, &run) {
87 env.options.set(Interactive, On);
88 }
89 if run.work.source == self::args::Source::Stdin {
90 env.options.set(Stdin, On);
91 }
92 for &(option, state) in &run.options {
93 env.options.set(option, state);
94 }
95 if env.options.get(Interactive) == On && !run.options.iter().any(|&(o, _)| o == Monitor) {
96 env.options.set(Monitor, On);
97 }
98
99 env.arg0 = run.arg0;
101 env.variables.positional_params_mut().values = run.positional_params;
102
103 if env.options.get(Interactive) == On {
105 env.traps
106 .enable_internal_dispositions_for_terminators(&env.system)
107 .await
108 .ok();
109 if env.options.get(Monitor) == On {
110 env.traps
111 .enable_internal_dispositions_for_stoppers(&env.system)
112 .await
113 .ok();
114 }
115 }
116
117 if env.options.get(Monitor) == On {
119 env.ensure_foreground().await.ok();
121 }
122
123 env.builtins.extend(yash_builtin::iter());
125
126 env.init_variables();
128
129 inject_dependencies(env);
131
132 run.work
133}
134
135fn inject_dependencies<S: Runtime + 'static>(env: &mut Env<S>) {
137 env.any
138 .insert(Box::new(SuspendedJobsGuardConfig::with_message(
139 "# There are stopped jobs. Type `exit -f` to exit anyway.\n",
140 )));
141 env.any.insert(Box::new(IgnoreEofConfig::with_message(
142 "# Type `exit` to leave the shell when the ignore-eof option is on.\n",
143 )));
144
145 env.any.insert(Box::new(IsKeyword::<S>(|_env, word| {
146 yash_syntax::parser::lex::Keyword::from_str(word).is_ok()
147 })));
148
149 env.any.insert(Box::new(IsName::<S>(|_env, name| {
150 yash_syntax::parser::lex::is_name(name)
151 })));
152
153 env.any.insert(Box::new(RunReadEvalLoop::<S>(|env, config| {
154 Box::pin(async move {
155 let mut lexer = Lexer::from(config);
156 yash_semantics::read_eval_loop(env, &mut lexer).await
157 })
158 })));
159
160 env.any.insert(Box::new(RunFunction::<S>(
161 |env, function, fields, env_prep_hook| {
162 Box::pin(async move {
163 yash_semantics::command::simple_command::execute_function_body(
164 env,
165 function,
166 fields,
167 env_prep_hook,
168 )
169 .await
170 })
171 },
172 )));
173
174 env.any
175 .insert(Box::new(RunSignalTrapIfCaught::<S>(|env, signal| {
176 Box::pin(async move { yash_semantics::trap::run_trap_if_caught(env, signal).await })
177 })));
178
179 env.any.insert(Box::new(ExpandText::<S>(|env, text| {
180 Box::pin(async move { expand_text(env, text).await.ok() })
181 })));
182
183 env.any.insert(Box::new(GetPrompt::<S>(|env, context| {
184 Box::pin(async move {
185 let prompt = yash_prompt::fetch_posix(&env.variables, context);
186 yash_prompt::expand_posix(env, &prompt, false).await
187 })
188 })));
189}