use async_trait::async_trait;
use std::path::PathBuf;
use super::{Builtin, Context};
use crate::error::Result;
use crate::interpreter::ExecResult;
pub struct Cd;
#[async_trait]
impl Builtin for Cd {
async fn execute(&self, ctx: Context<'_>) -> Result<ExecResult> {
let target = ctx
.args
.first()
.map(|s| s.as_str())
.or_else(|| ctx.variables.get("HOME").map(|s| s.as_str()))
.or_else(|| ctx.env.get("HOME").map(|s| s.as_str()))
.unwrap_or("/home/user");
let new_path = if target.starts_with('/') {
PathBuf::from(target)
} else if target == "-" {
ctx.variables
.get("OLDPWD")
.or_else(|| ctx.env.get("OLDPWD"))
.map(PathBuf::from)
.unwrap_or_else(|| ctx.cwd.clone())
} else {
ctx.cwd.join(target)
};
let normalized = normalize_path(&new_path);
if ctx.fs.exists(&normalized).await? {
let metadata = ctx.fs.stat(&normalized).await?;
if metadata.file_type.is_dir() {
let old_cwd = ctx.cwd.to_string_lossy().to_string();
ctx.variables.insert("OLDPWD".to_string(), old_cwd);
*ctx.cwd = normalized;
Ok(ExecResult::ok(""))
} else {
Ok(ExecResult::err(
format!("cd: {}: Not a directory\n", target),
1,
))
}
} else {
Ok(ExecResult::err(
format!("cd: {}: No such file or directory\n", target),
1,
))
}
}
}
pub struct Pwd;
#[async_trait]
impl Builtin for Pwd {
async fn execute(&self, ctx: Context<'_>) -> Result<ExecResult> {
let cwd = ctx.cwd.to_string_lossy();
Ok(ExecResult::ok(format!("{}\n", cwd)))
}
}
use crate::fs::normalize_path;