diff options
| author | Jonas Maier <jonas@x77.dev> | 2026-05-12 21:27:52 +0200 |
|---|---|---|
| committer | Jonas Maier <jonas@x77.dev> | 2026-05-12 21:27:52 +0200 |
| commit | 116b0ac3c99fd317d3800637ca3f88f4d3874c1b (patch) | |
| tree | 29982dbac0ed23275c960ff1be24600e7468cbf6 /src | |
| parent | 0e5d95663aaac8b7368c82290476694b561536d3 (diff) | |
| download | pish-116b0ac3c99fd317d3800637ca3f88f4d3874c1b.tar.gz | |
variable refactor: export builtin
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 2 | ||||
| -rw-r--r-- | src/run/builtin.rs | 25 | ||||
| -rw-r--r-- | src/run/mod.rs | 8 | ||||
| -rw-r--r-- | src/run/var.rs | 52 |
4 files changed, 79 insertions, 8 deletions
@@ -180,7 +180,7 @@ fn pretty_cwd() -> BString { impl Session { fn load_unevaled_prompt(&self) -> BString { match self.vars.lookup(&b"PROMPT"[..]) { - Some(prompt) => prompt.clone(), + Some(prompt) => prompt.into_owned(), None => { let mut prompt = BString::new(); if cfg!(debug_assertions) { diff --git a/src/run/builtin.rs b/src/run/builtin.rs index e928d8b..c8224c0 100644 --- a/src/run/builtin.rs +++ b/src/run/builtin.rs @@ -461,7 +461,7 @@ impl Builtin for var { } let se = session.lock().unwrap(); if let Some(val) = se.vars.lookup(&args[0]) { - stdout.write_all(val.as_slice())?; + stdout.write_all(val.as_ref())?; Ok(()) } else { Err(Error::Exit(1)) @@ -965,3 +965,26 @@ impl Builtin for logo { Ok(()) } } + +#[derive(Copy, Clone)] +pub struct export; + +impl Builtin for export { + fn name(&self) -> &str { + "export" + } + + fn io( + &self, + session: Arc<Mutex<Session>>, + args: &[BString], + _stdin: &mut dyn Read, + _stdout: &mut dyn Write, + ) -> Result { + let mut session = session.lock().unwrap(); + for v in args.iter() { + session.vars.allow_export(&v, true); + } + Ok(()) + } +} diff --git a/src/run/mod.rs b/src/run/mod.rs index 55bdd29..8be5fca 100644 --- a/src/run/mod.rs +++ b/src/run/mod.rs @@ -262,6 +262,11 @@ impl Executor { crate::export_fun::prepare_command(self.se.clone(), &mut command); + command.env_clear(); + for (var, val) in self.se.lock().unwrap().vars.export() { + command.env(OsStr::from_bytes(var), OsStr::from_bytes(val.as_ref())); + } + match command.spawn() { Ok(c) => SpawnedCmd::Child(ChildWaiter::new(c).unwrap()), Err(e) => SpawnedCmd::SpawnError(e), @@ -478,7 +483,7 @@ impl parse::Expander for Executor { } if let Some(val) = self.se.lock().unwrap().vars.lookup(&var) { - return Ok(val); + return Ok(val.into_owned()); } if let Some(dfl) = default { @@ -697,6 +702,7 @@ const BUILTINS: &[&'static dyn BuiltinClone] = &[ &builtin::Continue, &builtin::Here, &builtin::logo, + &builtin::export, ]; pub fn builtin_map() -> HashMap<BString, &'static dyn BuiltinClone> { diff --git a/src/run/var.rs b/src/run/var.rs index 0e64ad7..d3e98f4 100644 --- a/src/run/var.rs +++ b/src/run/var.rs @@ -1,4 +1,7 @@ +use std::borrow::Cow; use std::collections::{HashMap, HashSet}; +use std::sync::LazyLock; +use std::time::Instant; use crate::BString; use crate::bstr; @@ -7,6 +10,7 @@ pub struct Vars { simple: HashMap<BString, BString>, magic: HashMap<BString, fn() -> BString>, all: HashSet<BString>, + export: HashSet<BString>, } impl Vars { @@ -22,7 +26,15 @@ impl Vars { .cloned() .chain(magic.keys().cloned()) .collect(); - Self { simple, magic, all } + let export = std::env::vars_os() + .map(|x| x.0.into_encoded_bytes()) + .collect(); + Self { + simple, + magic, + all, + export, + } } pub fn set(&mut self, var: BString, val: BString) { @@ -30,18 +42,36 @@ impl Vars { self.all.insert(var); } - pub fn lookup(&self, var: &bstr) -> Option<BString> { + pub fn lookup<'a>(&'a self, var: &bstr) -> Option<Cow<'a, bstr>> { if let Some(fun) = self.magic.get(var) { - return Some(fun()); + return Some(Cow::Owned(fun())); } if let Some(val) = self.simple.get(var) { - return Some(val.clone()); + return Some(Cow::Borrowed(val)); } None } + pub fn allow_export(&mut self, var: &bstr, allow: bool) { + if allow { + self.export.insert(var.to_vec()); + } else { + self.export.remove(var); + } + } + + pub fn export<'a>(&'a self) -> HashMap<&'a bstr, Cow<'a, bstr>> { + self.export + .iter() + .filter_map(|var| { + let val = self.lookup(var)?; + Some((var.as_ref(), val)) + }) + .collect() + } + pub fn vars(&self) -> &HashSet<BString> { &self.all } @@ -62,9 +92,21 @@ impl Default for Vars { b"PISH_COMMIT" => crate::consts::PISH_COMMIT.as_bytes().to_vec(), b"PISH_DIRTY" => vec![crate::consts::PISH_DIRTY as u8 + b'0'], }; + let magic = map! { - b"CWD_PRETTY" => crate::pretty_cwd as _ + b"CWD_PRETTY" => crate::pretty_cwd as _, + b"SECONDS" => seconds_since_startup as _, }; + + // call it once such that lazylock gets initialized + seconds_since_startup(); + Self::new(simple, magic) } } + +static START: LazyLock<Instant> = LazyLock::new(Instant::now); + +fn seconds_since_startup() -> BString { + format!("{}", START.elapsed().as_secs_f64() as u64).into_bytes() +} |
