Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement cd - #201

Merged
merged 5 commits into from
Oct 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions brush-core/src/builtins/cd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use clap::Parser;

use crate::{builtins, commands};

/// Change the current working directory.
/// Change the current shell working directory.
#[derive(Parser)]
pub(crate) struct CdCommand {
/// Force following symlinks.
Expand All @@ -16,7 +16,7 @@ pub(crate) struct CdCommand {
#[arg(short = 'P')]
use_physical_dir: bool,

/// Exit if current working dir resolution fails.
/// Exit with non zero exit status if current working directory resolution fails.
#[arg(short = 'e')]
exit_on_failed_cwd_resolution: bool,

Expand All @@ -25,6 +25,8 @@ pub(crate) struct CdCommand {
#[arg(short = '@')]
file_with_xattr_as_dir: bool,

/// By default it is the value of the HOME shell variable. If `TARGET_DIR` is "-", it is
/// converted to $OLDPWD.
target_dir: Option<PathBuf>,
}

Expand All @@ -43,8 +45,22 @@ impl builtins::Command for CdCommand {
return crate::error::unimp("options to cd");
}

let mut should_print = false;
let target_dir = if let Some(target_dir) = &self.target_dir {
target_dir.clone()
// `cd -', equivalent to `cd $OLDPWD'
if target_dir.as_os_str() == "-" {
should_print = true;
if let Some(oldpwd) = context.shell.env.get_str("OLDPWD") {
PathBuf::from(oldpwd.to_string())
} else {
writeln!(context.stderr(), "OLDPWD not set")?;
return Ok(builtins::ExitCode::Custom(1));
}
} else {
// TODO: remove clone, and use temporary lifetime extension after rust 1.75
target_dir.clone()
}
// `cd' without arguments is equivalent to `cd $HOME'
} else {
if let Some(home_var) = context.shell.env.get_str("HOME") {
PathBuf::from(home_var.to_string())
Expand All @@ -54,12 +70,18 @@ impl builtins::Command for CdCommand {
}
};

match context.shell.set_working_dir(&target_dir) {
Ok(()) => {}
Err(e) => {
writeln!(context.stderr(), "cd: {e}")?;
return Ok(builtins::ExitCode::Custom(1));
}
if let Err(e) = context.shell.set_working_dir(&target_dir) {
writeln!(context.stderr(), "cd: {e}")?;
return Ok(builtins::ExitCode::Custom(1));
}

// Bash compatibility
// https://www.gnu.org/software/bash/manual/bash.html#index-cd
// If a non-empty directory name from CDPATH is used, or if '-' is the first argument, and
// the directory change is successful, the absolute pathname of the new working
// directory is written to the standard output.
if should_print {
writeln!(context.stdout(), "{}", target_dir.display())?;
}

Ok(builtins::ExitCode::Success)
Expand Down
14 changes: 12 additions & 2 deletions brush-core/src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -969,8 +969,6 @@ impl Shell {

let pwd = cleaned_path.to_string_lossy().to_string();

// TODO: handle updating PWD
self.working_dir = cleaned_path;
self.env.update_or_add(
"PWD",
variables::ShellValueLiteral::Scalar(pwd),
Expand All @@ -981,6 +979,18 @@ impl Shell {
EnvironmentLookup::Anywhere,
EnvironmentScope::Global,
)?;
let oldpwd = std::mem::replace(&mut self.working_dir, cleaned_path);

self.env.update_or_add(
"OLDPWD",
variables::ShellValueLiteral::Scalar(oldpwd.to_string_lossy().to_string()),
|var| {
var.export();
Ok(())
},
EnvironmentLookup::Anywhere,
EnvironmentScope::Global,
)?;

Ok(())
}
Expand Down
13 changes: 13 additions & 0 deletions brush-shell/tests/cases/builtins/cd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,16 @@ cases:
cd file
echo $?
ls -1

- name: "cd -"
ignore_stderr: true
stdin: |
cd /
echo "pwd: $PWD"
cd usr
echo "pwd: $PWD"
echo "oldpwd: $OLDPWD"
cd -
echo $?
echo "pwd: $PWD"

Loading