diff --git a/Cargo.lock b/Cargo.lock index 8b5a5ca2f..5fc7219ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2607,6 +2607,7 @@ dependencies = [ "crossterm", "fuzzy-matcher", "is_executable", + "lazy_static", "log", "miette 5.1.0", "nu-ansi-term", @@ -2619,6 +2620,7 @@ dependencies = [ "nu-test-support", "nu-utils", "reedline", + "regex", "sysinfo", "thiserror", ] diff --git a/crates/nu-cli/Cargo.toml b/crates/nu-cli/Cargo.toml index 4178c69de..4bd644aac 100644 --- a/crates/nu-cli/Cargo.toml +++ b/crates/nu-cli/Cargo.toml @@ -24,9 +24,11 @@ miette = { version = "5.1.0", features = ["fancy"] } thiserror = "1.0.31" fuzzy-matcher = "0.3.7" -log = "0.4" -is_executable = "1.0.1" chrono = "0.4.19" +is_executable = "1.0.1" +lazy_static = "1.4.0" +log = "0.4" +regex = "1.5.4" sysinfo = "0.24.1" [features] diff --git a/crates/nu-cli/src/repl.rs b/crates/nu-cli/src/repl.rs index 13c4db796..a702afd9f 100644 --- a/crates/nu-cli/src/repl.rs +++ b/crates/nu-cli/src/repl.rs @@ -5,6 +5,7 @@ use crate::{ util::{eval_source, get_guaranteed_cwd, report_error, report_error_new}, NuHighlighter, NuValidator, NushellPrompt, }; +use lazy_static::lazy_static; use log::{info, trace}; use miette::{IntoDiagnostic, Result}; use nu_color_config::get_color_config; @@ -16,6 +17,7 @@ use nu_protocol::{ BlockId, HistoryFileFormat, PipelineData, PositionalArg, ShellError, Span, Type, Value, VarId, }; use reedline::{DefaultHinter, Emacs, SqliteBackedHistory, Vi}; +use regex::Regex; use std::io::{self, Write}; use std::{sync::atomic::Ordering, time::Instant}; use sysinfo::SystemExt; @@ -335,13 +337,7 @@ pub fn evaluate_repl( let orig = s.clone(); - if (orig.starts_with('.') - || orig.starts_with('~') - || orig.starts_with('/') - || orig.starts_with('\\')) - && path.is_dir() - && tokens.0.len() == 1 - { + if looks_like_path(&orig) && path.is_dir() && tokens.0.len() == 1 { // We have an auto-cd let (path, span) = { if !path.exists() { @@ -756,3 +752,34 @@ fn run_ansi_sequence(seq: &str) -> Result<(), ShellError> { ) }) } + +lazy_static! { + // Absolute paths with a drive letter, like 'C:', 'D:\', 'E:\foo' + static ref DRIVE_PATH_REGEX: Regex = + Regex::new(r"^[a-zA-Z]:[/\\]?").expect("Internal error: regex creation"); +} + +// A best-effort "does this string look kinda like a path?" function to determine whether to auto-cd +fn looks_like_path(orig: &str) -> bool { + #[cfg(windows)] + { + if DRIVE_PATH_REGEX.is_match(orig) { + return true; + } + } + + orig.starts_with('.') + || orig.starts_with('~') + || orig.starts_with('/') + || orig.starts_with('\\') +} + +#[test] +fn looks_like_path_windows_drive_path_works() { + let on_windows = cfg!(windows); + assert_eq!(looks_like_path("C:"), on_windows); + assert_eq!(looks_like_path("D:\\"), on_windows); + assert_eq!(looks_like_path("E:/"), on_windows); + assert_eq!(looks_like_path("F:\\some_dir"), on_windows); + assert_eq!(looks_like_path("G:/some_dir"), on_windows); +}