Add automatic change directory (#1496)

* Allow automatic cd in cli mode

* Set correct priority for auto-cd and add test
This commit is contained in:
Jonathan Turner 2020-03-18 07:13:38 +13:00 committed by GitHub
parent 0d244a9701
commit 1ec2ec72b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 4 deletions

View File

@ -10,7 +10,10 @@ use crate::prelude::*;
use futures_codec::FramedRead;
use nu_errors::ShellError;
use nu_parser::{ClassifiedPipeline, PipelineShape, SpannedToken, TokensIterator};
use nu_parser::{
ClassifiedCommand, ClassifiedPipeline, ExternalCommand, PipelineShape, SpannedToken,
TokensIterator,
};
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
use log::{debug, log_enabled, trace};
@ -366,7 +369,7 @@ pub async fn run_pipeline_standalone(
redirect_stdin: bool,
context: &mut Context,
) -> Result<(), Box<dyn Error>> {
let line = process_line(Ok(pipeline), context, redirect_stdin).await;
let line = process_line(Ok(pipeline), context, redirect_stdin, false).await;
match line {
LineResult::Success(line) => {
@ -515,7 +518,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
initial_command = None;
}
let line = process_line(readline, &mut context, false).await;
let line = process_line(readline, &mut context, false, true).await;
// Check the config to see if we need to update the path
// TODO: make sure config is cached so we don't path this load every call
@ -598,6 +601,7 @@ async fn process_line(
readline: Result<String, ReadlineError>,
ctx: &mut Context,
redirect_stdin: bool,
cli_mode: bool,
) -> LineResult {
match &readline {
Ok(line) if line.trim() == "" => LineResult::Success(line.clone()),
@ -616,12 +620,32 @@ async fn process_line(
debug!("=== Parsed ===");
debug!("{:#?}", result);
let pipeline = classify_pipeline(&result, ctx, &Text::from(line));
let pipeline = classify_pipeline(&result, &ctx, &Text::from(line));
if let Some(failure) = pipeline.failed {
return LineResult::Error(line.to_string(), failure.into());
}
// There's a special case to check before we process the pipeline:
// If we're giving a path by itself
// ...and it's not a command in the path
// ...and it doesn't have any arguments
// ...and we're in the CLI
// ...then change to this directory
if cli_mode && pipeline.commands.list.len() == 1 {
if let ClassifiedCommand::External(ExternalCommand {
ref name, ref args, ..
}) = pipeline.commands.list[0]
{
if dunce::canonicalize(name).is_ok()
&& which::which(name).is_err()
&& args.list.is_empty()
{
ctx.shell_manager.set_path(name.to_string());
return LineResult::Success(line.to_string());
}
}
}
let input_stream = if redirect_stdin {
let file = futures::io::AllowStdIo::new(std::io::stdin());
let stream = FramedRead::new(file, MaybeTextCodec).map(|line| {

View File

@ -20,6 +20,25 @@ fn shows_error_for_command_not_found() {
assert!(actual.contains("Command not found"));
}
#[test]
fn automatically_change_directory() {
use nu_test_support::playground::Playground;
Playground::setup("cd_test_5_1", |dirs, sandbox| {
sandbox.within("autodir").mkdir("bar");
let actual = nu!(
cwd: dirs.test(),
r#"
autodir
pwd | echo $it
"#
);
assert!(actual.ends_with("autodir"));
})
}
mod it_evaluation {
use super::nu;
use nu_test_support::fs::Stub::{EmptyFile, FileWithContent, FileWithContentToBeTrimmed};