For example, when running the following:

    crates/nu-cli/src

nushell currently parses this as an external command. Before running the command, we check to see if
it's a directory. If it is, we "auto cd" into that directory, otherwise we go through normal
external processing.

If we put a trailing slash on it though, shells typically interpret that as "user is explicitly
referencing directory". So

    crates/nu-cli/src/

should not be interpreted as "run an external command". We intercept a trailing slash in the head
position of a command in a pipeline as such, and inject a `cd` internal command.
This commit is contained in:
Jason Gedge
2020-04-26 21:22:01 -04:00
committed by GitHub
parent 80025ea684
commit 6f2ef05195
9 changed files with 223 additions and 85 deletions

View File

@ -1,3 +1,4 @@
use crate::commands::cd::CdArgs;
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
@ -10,9 +11,7 @@ use crate::prelude::*;
use crate::shell::completer::NuCompleter;
use crate::shell::shell::Shell;
use crate::utils::FileStructure;
use nu_errors::ShellError;
use nu_parser::expand_ndots;
use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue};
use rustyline::completion::FilenameCompleter;
use rustyline::hint::{Hinter, HistoryHinter};
use std::collections::HashMap;
@ -21,6 +20,11 @@ use std::path::{Component, Path, PathBuf};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
use nu_errors::ShellError;
use nu_parser::expand_ndots;
use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue};
use nu_source::Tagged;
pub struct FilesystemShell {
pub(crate) path: String,
pub(crate) last_path: String,
@ -171,21 +175,20 @@ impl Shell for FilesystemShell {
Ok(stream.interruptible(ctrl_c).to_output_stream())
}
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
let path = match args.nth(0) {
fn cd(&self, args: CdArgs, name: Tag) -> Result<OutputStream, ShellError> {
let path = match args.path {
None => match dirs::home_dir() {
Some(o) => o,
_ => {
return Err(ShellError::labeled_error(
"Cannot change to home directory",
"cannot go to home",
&args.call_info.name_tag,
&name,
))
}
},
Some(v) => {
let target = v.as_path()?;
let Tagged { item: target, tag } = v;
if target == Path::new("-") {
PathBuf::from(&self.last_path)
} else {
@ -193,7 +196,7 @@ impl Shell for FilesystemShell {
ShellError::labeled_error(
"Cannot change to directory",
"directory not found",
&v.tag,
&tag,
)
})?;
@ -201,7 +204,7 @@ impl Shell for FilesystemShell {
return Err(ShellError::labeled_error(
"Cannot change to directory",
"is not a directory",
&v.tag,
&tag,
));
}
@ -216,7 +219,7 @@ impl Shell for FilesystemShell {
ShellError::labeled_error(
"Cannot change to directory",
format!("cannot stat ({})", e),
&v.tag,
&tag,
)
})?;
@ -224,7 +227,7 @@ impl Shell for FilesystemShell {
return Err(ShellError::labeled_error(
"Cannot change to directory",
"permission denied",
&v.tag,
&tag,
));
}
}

View File

@ -1,3 +1,4 @@
use crate::commands::cd::CdArgs;
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
@ -7,12 +8,15 @@ use crate::commands::rm::RemoveArgs;
use crate::data::command_dict;
use crate::prelude::*;
use crate::shell::shell::Shell;
use std::ffi::OsStr;
use std::path::PathBuf;
use nu_errors::ShellError;
use nu_protocol::{
Primitive, ReturnSuccess, ShellTypeName, TaggedDictBuilder, UntaggedValue, Value,
};
use std::ffi::OsStr;
use std::path::PathBuf;
use nu_source::Tagged;
#[derive(Clone, Debug)]
pub struct HelpShell {
@ -149,12 +153,11 @@ impl Shell for HelpShell {
Ok(output.into())
}
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
let path = match args.nth(0) {
fn cd(&self, args: CdArgs, _name: Tag) -> Result<OutputStream, ShellError> {
let path = match args.path {
None => "/".to_string(),
Some(v) => {
let target = v.as_path()?;
let Tagged { item: target, .. } = v;
let mut cwd = PathBuf::from(&self.path);
if target == PathBuf::from("..") {

View File

@ -1,3 +1,4 @@
use crate::commands::cd::CdArgs;
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
@ -18,7 +19,7 @@ pub trait Shell: std::fmt::Debug {
args: LsArgs,
context: &RunnablePerItemContext,
) -> Result<OutputStream, ShellError>;
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>;
fn cd(&self, args: CdArgs, name: Tag) -> Result<OutputStream, ShellError>;
fn cp(&self, args: CopyArgs, name: Tag, path: &str) -> Result<OutputStream, ShellError>;
fn mkdir(&self, args: MkdirArgs, name: Tag, path: &str) -> Result<OutputStream, ShellError>;
fn mv(&self, args: MoveArgs, name: Tag, path: &str) -> Result<OutputStream, ShellError>;

View File

@ -1,3 +1,4 @@
use crate::commands::cd::CdArgs;
use crate::commands::command::{EvaluatedWholeStreamCommandArgs, RunnablePerItemContext};
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
@ -141,10 +142,10 @@ impl ShellManager {
env[self.current_shell()].ls(args, context)
}
pub fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
pub fn cd(&self, args: CdArgs, context: &RunnableContext) -> Result<OutputStream, ShellError> {
let env = self.shells.lock();
env[self.current_shell()].cd(args)
env[self.current_shell()].cd(args, context.name.clone())
}
pub fn cp(

View File

@ -1,3 +1,4 @@
use crate::commands::cd::CdArgs;
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
@ -7,11 +8,14 @@ use crate::commands::rm::RemoveArgs;
use crate::prelude::*;
use crate::shell::shell::Shell;
use crate::utils::ValueStructure;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, ShellTypeName, UntaggedValue, Value};
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, ShellTypeName, UntaggedValue, Value};
use nu_source::Tagged;
#[derive(Clone)]
pub struct ValueShell {
pub(crate) path: String,
@ -127,19 +131,18 @@ impl Shell for ValueShell {
Ok(output.into())
}
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
let destination = args.nth(0);
fn cd(&self, args: CdArgs, name: Tag) -> Result<OutputStream, ShellError> {
let destination = args.path;
let path = match destination {
None => "/".to_string(),
Some(v) => {
let target = v.as_path()?;
Some(ref v) => {
let Tagged { item: target, .. } = v;
let mut cwd = PathBuf::from(&self.path);
if target == PathBuf::from("..") {
if target == &PathBuf::from("..") {
cwd.pop();
} else if target == PathBuf::from("-") {
} else if target == &PathBuf::from("-") {
cwd = PathBuf::from(&self.last_path);
} else {
match target.to_str() {
@ -169,7 +172,7 @@ impl Shell for ValueShell {
return Err(ShellError::labeled_error(
"Can not change to path inside",
"No such path exists",
&args.call_info.name_tag,
&name,
));
}