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