mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-13 07:21:13 -03:00
committed by
Peter Ammon
parent
de0e519b22
commit
411a43254b
@@ -12,7 +12,6 @@
|
||||
use errno::Errno;
|
||||
use libc::{EACCES, ELOOP, ENOENT, ENOTDIR, EPERM};
|
||||
use nix::unistd::fchdir;
|
||||
use std::sync::Arc;
|
||||
|
||||
// cd is highlighted specially in src/highlight/highlight.rs - new options also need to be added
|
||||
// there
|
||||
@@ -23,6 +22,31 @@
|
||||
wopt(L!("dereference"), ArgType::NoArgument, 'P'),
|
||||
];
|
||||
|
||||
fn try_chdir(dirs: Vec<WString>, parser: &mut Parser, deref_symlink: bool) -> bool {
|
||||
for dir in dirs {
|
||||
let norm_dir = normalize_path(&dir, true);
|
||||
if let Ok(fd) = wopen_dir(&norm_dir, BEST_O_SEARCH) {
|
||||
if fchdir(&fd).is_ok() {
|
||||
parser.libdata_mut().cwd_fd = Some(std::sync::Arc::new(fd));
|
||||
|
||||
let mut new_pwd = norm_dir;
|
||||
if deref_symlink {
|
||||
if let Some(real_dir) = wrealpath(&new_pwd) {
|
||||
new_pwd = real_dir;
|
||||
}
|
||||
}
|
||||
parser.set_var_and_fire(
|
||||
L!("PWD"),
|
||||
ParserEnvSetMode::new(EnvMode::EXPORT | EnvMode::GLOBAL),
|
||||
vec![new_pwd],
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// The cd builtin. Changes the current directory to the one specified or to $HOME if none is
|
||||
// specified. The directory can be relative to any directory in the CDPATH variable.
|
||||
pub fn cd(parser: &mut Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> BuiltinResult {
|
||||
@@ -107,6 +131,18 @@ pub fn cd(parser: &mut Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> B
|
||||
}
|
||||
}
|
||||
|
||||
let is_relative_to_cwd = [L!("."), L!("..")].contains(&dir_in)
|
||||
|| dir_in.starts_with(L!("./"))
|
||||
|| dir_in.starts_with(L!("../"));
|
||||
if is_relative_to_cwd && wopen_dir(&normalize_path(&pwd, true), BEST_O_SEARCH).is_err() {
|
||||
if let Some(mut real_pwd) = wrealpath(L!(".")) {
|
||||
if !real_pwd.ends_with('/') {
|
||||
real_pwd.push('/');
|
||||
}
|
||||
pwd = real_pwd;
|
||||
}
|
||||
}
|
||||
|
||||
let dirs = path_apply_cdpath(dir_in, &pwd, vars);
|
||||
assert!(
|
||||
!dirs.is_empty(),
|
||||
@@ -133,7 +169,7 @@ pub fn cd(parser: &mut Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> B
|
||||
.map(|()| fd)
|
||||
});
|
||||
|
||||
let fd = match res {
|
||||
let _fd = match res {
|
||||
Ok(fd) => fd,
|
||||
Err(err) => {
|
||||
// Some errors we skip and only report if nothing worked.
|
||||
@@ -158,23 +194,9 @@ pub fn cd(parser: &mut Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> B
|
||||
}
|
||||
};
|
||||
|
||||
// Stash the fd for the cwd in the parser so it stays open.
|
||||
// Eventually fish will support distinct CWDs for different parsers in different threads.
|
||||
parser.libdata_mut().cwd_fd = Some(Arc::new(fd));
|
||||
|
||||
let mut new_pwd = norm_dir;
|
||||
if deref_symlink {
|
||||
if let Some(real_dir) = wrealpath(&new_pwd) {
|
||||
new_pwd = real_dir;
|
||||
}
|
||||
if try_chdir(vec![dir], parser, deref_symlink) {
|
||||
return Ok(SUCCESS);
|
||||
}
|
||||
|
||||
parser.set_var_and_fire(
|
||||
L!("PWD"),
|
||||
ParserEnvSetMode::new(EnvMode::EXPORT | EnvMode::GLOBAL),
|
||||
vec![new_pwd],
|
||||
);
|
||||
return Ok(SUCCESS);
|
||||
}
|
||||
|
||||
let mut err = if best_errno == ENOTDIR {
|
||||
|
||||
@@ -430,3 +430,19 @@ cd (string repeat 4096 a)
|
||||
# named "bin")
|
||||
cd /
|
||||
cd bin
|
||||
|
||||
# Test that cd works after the current directory has been moved (issue #12700)
|
||||
if __fish_is_cygwin
|
||||
# Not supported on Cygwin/MSYS. Satisfy the CHECK below.
|
||||
echo "cd after move succeeded"
|
||||
else
|
||||
set -l tmp (mktemp -d)
|
||||
set -l tmp_moved {$tmp}_moved
|
||||
cd $tmp
|
||||
mv $tmp $tmp_moved
|
||||
cd .
|
||||
test $PWD = $tmp_moved
|
||||
and echo "cd after move succeeded"
|
||||
cd $tmp_moved
|
||||
end
|
||||
# CHECK: cd after move succeeded
|
||||
|
||||
Reference in New Issue
Block a user