summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2022-01-17 00:05:00 -0500
committerJesse Luehrs <doy@tozt.net>2022-01-17 00:05:00 -0500
commite7d8a9f7d234cb2b8a6691c5a2e33f2b18776a3d (patch)
tree84eac0ddc63e529275f48071adfdfefd1cdc1c0a
parenta537464a915aea2e38c62df041996b8525367bde (diff)
downloadnbsh-e7d8a9f7d234cb2b8a6691c5a2e33f2b18776a3d.tar.gz
nbsh-e7d8a9f7d234cb2b8a6691c5a2e33f2b18776a3d.zip
simplify environment handling
this temporarily breaks cd history, will fix this soon
-rw-r--r--src/env.rs218
-rw-r--r--src/parse/ast.rs4
-rw-r--r--src/runner/builtins/mod.rs14
-rw-r--r--src/runner/mod.rs5
-rw-r--r--src/shell/history/entry.rs2
-rw-r--r--src/shell/mod.rs4
-rw-r--r--src/shell/readline.rs2
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<std::path::PathBuf>,
vars: std::collections::HashMap<std::ffi::OsString, std::ffi::OsString>,
}
+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<Self> {
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<String> {
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<String> {
- 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<Item = (std::ffi::OsString, std::ffi::OsString)>,
- ) {
- 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<S>(
- status: &std::process::ExitStatus,
- s: S,
-) -> Result<S::Ok, S::Error>
-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<std::process::ExitStatus, D::Error>
-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<S>(
- prev_pwd: &crate::mutex::Mutex<std::path::PathBuf>,
- s: S,
-) -> Result<S::Ok, S::Error>
-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<crate::mutex::Mutex<std::path::PathBuf>, 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<command::Child> {
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<i32> {
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<Event>,
) {
- 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<i32> {
}
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)?;