From 30e37c7f6e3e69fefc709b6be5bcfb3a647909fc Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 15 Jan 2022 15:26:56 -0500 Subject: implement `cd -` --- src/env.rs | 75 +++++++++++++++++++++++++++++++++++++--------- src/prelude.rs | 2 +- src/runner/builtins/mod.rs | 26 ++++++++++++++-- 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, vars: std::collections::HashMap, } @@ -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, - ) { + 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, + ) { + 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( + 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/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) } -- cgit v1.2.3-54-g00ecf