use self::args::{Run, Source, Work};
use std::str::FromStr as _;
use yash_env::Env;
use yash_env::io::Fd;
use yash_env::option::Option::{Interactive, Monitor, Stdin};
use yash_env::option::State::On;
use yash_env::parser::IsKeyword;
use yash_env::parser::IsName;
use yash_env::prompt::GetPrompt;
use yash_env::semantics::command::RunFunction;
use yash_env::system::resource::GetRlimit;
use yash_env::system::{Chdir, GetCwd, GetUid, Isatty, Sysconf, TcGetPgrp, Times, Umask};
use yash_env::trap::RunSignalTrapIfCaught;
use yash_prompt::ExpandText;
use yash_semantics::expansion::expand_text;
use yash_semantics::{RunReadEvalLoop, Runtime};
use yash_syntax::parser::lex::Lexer;
pub mod args;
pub mod init_file;
pub mod input;
pub fn auto_interactive<S: Isatty>(system: &S, run: &Run) -> bool {
if run.work.source != Source::Stdin {
return false;
}
if run.options.iter().any(|&(o, _)| o == Interactive) {
return false;
}
system.isatty(Fd::STDIN) && system.isatty(Fd::STDERR)
}
pub async fn configure_environment<S>(env: &mut Env<S>, run: Run) -> Work
where
S: Chdir
+ GetCwd
+ GetRlimit
+ GetUid
+ Runtime
+ Sysconf
+ TcGetPgrp
+ Times
+ Umask
+ 'static,
{
if auto_interactive(&env.system, &run) {
env.options.set(Interactive, On);
}
if run.work.source == self::args::Source::Stdin {
env.options.set(Stdin, On);
}
for &(option, state) in &run.options {
env.options.set(option, state);
}
if env.options.get(Interactive) == On && !run.options.iter().any(|&(o, _)| o == Monitor) {
env.options.set(Monitor, On);
}
env.arg0 = run.arg0;
env.variables.positional_params_mut().values = run.positional_params;
if env.options.get(Interactive) == On {
env.traps
.enable_internal_dispositions_for_terminators(&env.system)
.await
.ok();
if env.options.get(Monitor) == On {
env.traps
.enable_internal_dispositions_for_stoppers(&env.system)
.await
.ok();
}
}
if env.options.get(Monitor) == On {
env.ensure_foreground().await.ok();
}
env.builtins.extend(yash_builtin::iter());
env.init_variables();
inject_dependencies(env);
run.work
}
fn inject_dependencies<S: Runtime + 'static>(env: &mut Env<S>) {
env.any.insert(Box::new(IsKeyword::<S>(|_env, word| {
yash_syntax::parser::lex::Keyword::from_str(word).is_ok()
})));
env.any.insert(Box::new(IsName::<S>(|_env, name| {
yash_syntax::parser::lex::is_name(name)
})));
env.any.insert(Box::new(RunReadEvalLoop::<S>(|env, config| {
Box::pin(async move {
let mut lexer = Lexer::from(config);
yash_semantics::read_eval_loop(env, &mut lexer).await
})
})));
env.any.insert(Box::new(RunFunction::<S>(
|env, function, fields, env_prep_hook| {
Box::pin(async move {
yash_semantics::command::simple_command::execute_function_body(
env,
function,
fields,
env_prep_hook,
)
.await
})
},
)));
env.any
.insert(Box::new(RunSignalTrapIfCaught::<S>(|env, signal| {
Box::pin(async move { yash_semantics::trap::run_trap_if_caught(env, signal).await })
})));
env.any.insert(Box::new(ExpandText::<S>(|env, text| {
Box::pin(async move { expand_text(env, text).await.ok() })
})));
env.any.insert(Box::new(GetPrompt::<S>(|env, context| {
Box::pin(async move {
let prompt = yash_prompt::fetch_posix(&env.variables, context);
yash_prompt::expand_posix(env, &prompt, false).await
})
})));
}