From e7d8a9f7d234cb2b8a6691c5a2e33f2b18776a3d Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 17 Jan 2022 00:05:00 -0500 Subject: simplify environment handling this temporarily breaks cd history, will fix this soon --- src/env.rs | 218 ++++++++++++++------------------------------- src/parse/ast.rs | 4 +- src/runner/builtins/mod.rs | 14 +-- src/runner/mod.rs | 5 +- src/shell/history/entry.rs | 2 +- src/shell/mod.rs | 4 +- src/shell/readline.rs | 2 +- 7 files changed, 87 insertions(+), 162 deletions(-) diff --git a/src/env.rs b/src/env.rs index 981d8fc..b612d60 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,7 +1,5 @@ use crate::prelude::*; -use serde::Deserialize as _; - #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum Env { V0(V0), @@ -9,72 +7,44 @@ pub enum Env { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct V0 { - idx: usize, - #[serde( - serialize_with = "serialize_status", - deserialize_with = "deserialize_status" - )] - latest_status: async_std::process::ExitStatus, pwd: std::path::PathBuf, - #[serde( - serialize_with = "serialize_prev_pwd", - deserialize_with = "deserialize_prev_pwd" - )] - prev_pwd: crate::mutex::Mutex, vars: std::collections::HashMap, } +const __NBSH_IDX: &str = "__NBSH_IDX"; +const __NBSH_LATEST_STATUS: &str = "__NBSH_LATEST_STATUS"; +const __NBSH_PREV_PWD: &str = "__NBSH_PREV_PWD"; + impl Env { pub fn new() -> anyhow::Result { let pwd = std::env::current_dir()?; Ok(Self::V0(V0 { - idx: 0, - latest_status: std::process::ExitStatus::from_raw(0), pwd: pwd.clone(), - prev_pwd: crate::mutex::new(pwd), - vars: std::env::vars_os().collect(), + vars: std::env::vars_os() + .chain( + [ + (__NBSH_IDX.into(), "0".into()), + (__NBSH_LATEST_STATUS.into(), "0".into()), + (__NBSH_PREV_PWD.into(), pwd.into()), + ] + .into_iter(), + ) + .collect(), })) } - pub fn idx(&self) -> usize { - match self { - Self::V0(env) => env.idx, - } - } - - pub fn set_idx(&mut self, idx: usize) { - match self { - Self::V0(env) => env.idx = idx, - } - } - - pub fn latest_status(&self) -> &async_std::process::ExitStatus { - match self { - Self::V0(env) => &env.latest_status, - } - } - - pub fn set_status(&mut self, status: async_std::process::ExitStatus) { - match self { - Self::V0(env) => { - env.latest_status = status; - } - } - } - - pub fn current_dir(&self) -> &std::path::Path { + pub fn pwd(&self) -> &std::path::Path { match self { Self::V0(env) => &env.pwd, } } - pub fn var(&self, k: &str) -> String { + pub fn var(&self, k: &str) -> Option { match self { - Self::V0(env) => self.special_var(k).unwrap_or_else(|| { - env.vars.get(std::ffi::OsStr::new(k)).map_or_else( - || "".to_string(), - |v| v.to_str().unwrap().to_string(), - ) + Self::V0(env) => self.special_var(k).or_else(|| { + env.vars + .get(std::ffi::OsStr::new(k)) + .map(|v| v.to_str().unwrap().to_string()) }), } } @@ -94,18 +64,37 @@ impl Env { } } - pub async fn prev_pwd(&self) -> std::path::PathBuf { - match self { - Self::V0(env) => env.prev_pwd.lock_arc().await.clone(), - } + pub fn idx(&self) -> usize { + self.var(__NBSH_IDX).unwrap().parse().unwrap() } - pub async fn set_prev_pwd(&self, prev_pwd: &std::path::Path) { - match self { - Self::V0(env) => { - *env.prev_pwd.lock_arc().await = prev_pwd.to_path_buf(); - } - } + pub fn set_idx(&mut self, idx: usize) { + self.set_var(__NBSH_IDX, format!("{}", idx)); + } + + pub fn latest_status(&self) -> std::process::ExitStatus { + std::process::ExitStatus::from_raw( + self.var(__NBSH_LATEST_STATUS).unwrap().parse().unwrap(), + ) + } + + pub fn set_status(&mut self, status: std::process::ExitStatus) { + self.set_var( + __NBSH_LATEST_STATUS, + format!( + "{}", + (status.code().unwrap_or(0) << 8) + | status.signal().unwrap_or(0) + ), + ); + } + + pub fn prev_pwd(&self) -> std::path::PathBuf { + std::path::PathBuf::from(self.var(__NBSH_PREV_PWD).unwrap()) + } + + pub fn set_prev_pwd(&mut self, prev_pwd: std::path::PathBuf) { + self.set_var(__NBSH_PREV_PWD, prev_pwd); } pub fn apply(&self, cmd: &mut pty_process::Command) { @@ -118,13 +107,14 @@ impl Env { } } - pub fn update( - &mut self, - status: std::process::ExitStatus, - ) -> anyhow::Result<()> { + pub fn update(&mut self) -> anyhow::Result<()> { + let idx = self.idx(); + let status = self.latest_status(); + let prev_pwd = self.prev_pwd(); + *self = Self::new()?; + self.set_idx(idx); self.set_status(status); - self.set_current_dir(std::env::current_dir()?); - self.set_vars(std::env::vars_os()); + self.set_prev_pwd(prev_pwd); Ok(()) } @@ -137,89 +127,19 @@ impl Env { } fn special_var(&self, k: &str) -> Option { - match self { - Self::V0(env) => Some(match k { - "$" => crate::info::pid(), - "?" => { - let status = env.latest_status; - status - .signal() - .map_or_else( - || status.code().unwrap(), - |signal| signal + 128, - ) - .to_string() - } - _ => return None, - }), - } - } - - fn set_current_dir(&mut self, pwd: std::path::PathBuf) { - match self { - Self::V0(env) => { - env.pwd = pwd; - } - } - } - - fn set_vars( - &mut self, - it: impl Iterator, - ) { - match self { - Self::V0(env) => { - env.vars = it.collect(); + Some(match k { + "$" => crate::info::pid(), + "?" => { + let status = self.latest_status(); + status + .signal() + .map_or_else( + || status.code().unwrap(), + |signal| signal + 128, + ) + .to_string() } - } + _ => return None, + }) } } - -#[allow(clippy::trivially_copy_pass_by_ref)] -fn serialize_status( - status: &std::process::ExitStatus, - s: S, -) -> Result -where - S: serde::Serializer, -{ - let code: u16 = status.code().unwrap_or(0).try_into().unwrap(); - let signal: u16 = status.signal().unwrap_or(0).try_into().unwrap(); - s.serialize_u16((code << 8) | signal) -} - -fn deserialize_status<'de, D>( - d: D, -) -> Result -where - D: serde::Deserializer<'de>, -{ - let status = u16::deserialize(d)?; - Ok(std::process::ExitStatus::from_raw(i32::from(status))) -} - -#[allow(clippy::trivially_copy_pass_by_ref)] -fn serialize_prev_pwd( - prev_pwd: &crate::mutex::Mutex, - s: S, -) -> Result -where - S: serde::Serializer, -{ - s.serialize_bytes( - async_std::task::block_on(async { prev_pwd.lock_arc().await }) - .as_os_str() - .as_bytes(), - ) -} - -fn deserialize_prev_pwd<'de, D>( - d: D, -) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - Ok(crate::mutex::new(std::path::PathBuf::from( - std::ffi::OsString::from_vec(Vec::deserialize(d)?), - ))) -} diff --git a/src/parse/ast.rs b/src/parse/ast.rs index 88ae734..bac40c8 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -330,7 +330,9 @@ impl WordPart { fn eval(self, env: &Env) -> String { match self { Self::Alternation(_) => unreachable!(), - Self::Var(name) => env.var(&name), + Self::Var(name) => { + env.var(&name).unwrap_or_else(|| "".to_string()) + } Self::Bareword(s) | Self::DoubleQuoted(s) | Self::SingleQuoted(s) => s, diff --git a/src/runner/builtins/mod.rs b/src/runner/builtins/mod.rs index c345a85..f181b45 100644 --- a/src/runner/builtins/mod.rs +++ b/src/runner/builtins/mod.rs @@ -67,16 +67,17 @@ fn cd( if dir.is_empty() { ".".to_string().into() } else if dir == "-" { - env.prev_pwd().await + env.prev_pwd() } else { dir.into() } } else { let dir = env.var("HOME"); - if dir.is_empty() { + if let Some(dir) = dir { + dir.into() + } else { bail!(cfg, exe, "could not find home directory"); } - dir.into() }; let prev = match std::env::current_dir() { Ok(path) => path, @@ -98,7 +99,8 @@ fn cd( dir.display() ); } - env.set_prev_pwd(&prev).await; + // TODO + // env.set_prev_pwd(prev); async_std::process::ExitStatus::from_raw(0) } @@ -255,7 +257,7 @@ fn and( cfg.setup_command(&mut cmd); Ok(command::Child::new_wrapped(cmd.spawn(env)?)) } else { - let status = *env.latest_status(); + let status = env.latest_status(); Ok(command::Child::new_fut(async move { status })) } } @@ -267,7 +269,7 @@ fn or( ) -> anyhow::Result { exe.shift(); if env.latest_status().success() { - let status = *env.latest_status(); + let status = env.latest_status(); Ok(command::Child::new_fut(async move { status })) } else { let mut cmd = crate::runner::Command::new(exe, cfg.io().clone()); diff --git a/src/runner/mod.rs b/src/runner/mod.rs index a2db255..21ed9c9 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -79,7 +79,7 @@ pub async fn main() -> anyhow::Result { let (commands, mut env) = read_data(shell_read).await?; run_commands(&commands, &mut env, &shell_write).await?; - let status = *env.latest_status(); + let status = env.latest_status(); write_event(&shell_write, Event::Exit(env)).await?; if let Some(signal) = status.signal() { @@ -216,7 +216,8 @@ async fn run_pipeline( let (children, pg) = spawn_children(pipeline, env, &io)?; let status = wait_children(children, pg, env, &io, shell_write).await; set_foreground_pg(nix::unistd::getpid())?; - env.update(status)?; + env.update()?; + env.set_status(status); Ok(()) } diff --git a/src/shell/history/entry.rs b/src/shell/history/entry.rs index 01aad8b..a45d99d 100644 --- a/src/shell/history/entry.rs +++ b/src/shell/history/entry.rs @@ -343,7 +343,7 @@ impl Entry { env: Env, event_w: async_std::channel::Sender, ) { - self.state = State::Exited(ExitInfo::new(*env.latest_status())); + self.state = State::Exited(ExitInfo::new(env.latest_status())); self.env = env; event_w.send(Event::PtyClose).await.unwrap(); } diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 8343b0e..f7080a4 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -147,11 +147,11 @@ pub async fn main() -> anyhow::Result { } let mut shell = Shell::new(crate::info::get_offset())?; - let mut prev_dir = shell.env.current_dir().to_path_buf(); + let mut prev_dir = shell.env.pwd().to_path_buf(); git_w.send(prev_dir.clone()).await.unwrap(); let event_reader = event::Reader::new(event_r); while let Some(event) = event_reader.recv().await { - let dir = shell.env().current_dir(); + let dir = shell.env().pwd(); if dir != prev_dir { prev_dir = dir.to_path_buf(); git_w.send(dir.to_path_buf()).await.unwrap(); diff --git a/src/shell/readline.rs b/src/shell/readline.rs index ffe92fe..f0fb950 100644 --- a/src/shell/readline.rs +++ b/src/shell/readline.rs @@ -27,7 +27,7 @@ impl Readline { focus: bool, offset: time::UtcOffset, ) -> anyhow::Result<()> { - let pwd = env.current_dir(); + let pwd = env.pwd(); let user = crate::info::user()?; let hostname = crate::info::hostname()?; let time = crate::info::time(offset)?; -- cgit v1.2.3-54-g00ecf