summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2022-01-15 15:26:56 -0500
committerJesse Luehrs <doy@tozt.net>2022-01-15 15:26:56 -0500
commit30e37c7f6e3e69fefc709b6be5bcfb3a647909fc (patch)
treeb5f2b78cdb541b9ce1dbbedbf21707327e68975b
parent3adc8b67354a492f4bceed4b9bf1ec5c000c2056 (diff)
downloadnbsh-30e37c7f6e3e69fefc709b6be5bcfb3a647909fc.tar.gz
nbsh-30e37c7f6e3e69fefc709b6be5bcfb3a647909fc.zip
implement `cd -`
-rw-r--r--src/env.rs75
-rw-r--r--src/prelude.rs2
-rw-r--r--src/runner/builtins/mod.rs26
3 files changed, 85 insertions, 18 deletions
diff --git a/src/env.rs b/src/env.rs
index 6ac67f5..bf6cb6c 100644
--- a/src/env.rs
+++ b/src/env.rs
@@ -16,6 +16,11 @@ pub struct V0 {
)]
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>,
}
@@ -27,10 +32,12 @@ impl Env {
> = std::env::vars_os().collect();
vars.insert("SHELL".into(), std::env::current_exe()?.into());
vars.insert("TERM".into(), "screen".into());
+ let pwd = std::env::current_dir()?;
Ok(Self::V0(V0 {
idx: 0,
latest_status: std::process::ExitStatus::from_raw(0),
- pwd: std::env::current_dir()?,
+ pwd: pwd.clone(),
+ prev_pwd: crate::mutex::new(pwd),
vars,
}))
}
@@ -67,14 +74,6 @@ impl Env {
}
}
- pub fn set_current_dir(&mut self, pwd: std::path::PathBuf) {
- match self {
- Self::V0(env) => {
- env.pwd = pwd;
- }
- }
- }
-
pub fn var(&self, k: &str) -> String {
match self {
Self::V0(env) => self.special_var(k).unwrap_or_else(|| {
@@ -94,13 +93,16 @@ impl Env {
}
}
- pub fn set_vars(
- &mut self,
- it: impl Iterator<Item = (std::ffi::OsString, std::ffi::OsString)>,
- ) {
+ pub async fn prev_pwd(&self) -> std::path::PathBuf {
+ match self {
+ Self::V0(env) => env.prev_pwd.lock_arc().await.clone(),
+ }
+ }
+
+ pub async fn set_prev_pwd(&self, prev_pwd: &std::path::Path) {
match self {
Self::V0(env) => {
- env.vars = it.collect();
+ *env.prev_pwd.lock_arc().await = prev_pwd.to_path_buf();
}
}
}
@@ -151,6 +153,25 @@ impl Env {
}),
}
}
+
+ 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();
+ }
+ }
+ }
}
#[allow(clippy::trivially_copy_pass_by_ref)]
@@ -175,3 +196,29 @@ where
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/prelude.rs b/src/prelude.rs
index 8c888c8..6789a1f 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -5,7 +5,7 @@ pub use async_std::stream::StreamExt as _;
pub use futures_lite::future::FutureExt as _;
pub use async_std::os::unix::process::CommandExt as _;
-pub use std::os::unix::ffi::OsStrExt as _;
+pub use std::os::unix::ffi::{OsStrExt as _, OsStringExt as _};
pub use std::os::unix::io::{AsRawFd as _, FromRawFd as _, IntoRawFd as _};
pub use std::os::unix::process::ExitStatusExt as _;
pub use users::os::unix::UserExt as _;
diff --git a/src/runner/builtins/mod.rs b/src/runner/builtins/mod.rs
index ff03499..c345a85 100644
--- a/src/runner/builtins/mod.rs
+++ b/src/runner/builtins/mod.rs
@@ -65,7 +65,9 @@ fn cd(
) -> std::process::ExitStatus {
let dir = if let Some(dir) = exe.args().get(0) {
if dir.is_empty() {
- ".".to_string()
+ ".".to_string().into()
+ } else if dir == "-" {
+ env.prev_pwd().await
} else {
dir.into()
}
@@ -74,11 +76,29 @@ fn cd(
if dir.is_empty() {
bail!(cfg, exe, "could not find home directory");
}
- dir
+ dir.into()
+ };
+ let prev = match std::env::current_dir() {
+ Ok(path) => path,
+ Err(e) => {
+ bail!(
+ cfg,
+ exe,
+ "could not find current directory: {}",
+ crate::format::io_error(&e)
+ );
+ }
};
if let Err(e) = std::env::set_current_dir(&dir) {
- bail!(cfg, exe, "{}: {}", crate::format::io_error(&e), dir);
+ bail!(
+ cfg,
+ exe,
+ "{}: {}",
+ crate::format::io_error(&e),
+ dir.display()
+ );
}
+ env.set_prev_pwd(&prev).await;
async_std::process::ExitStatus::from_raw(0)
}