diff --git a/src/main.rs b/src/main.rs index 80e380fe9..cf4219760 100644 --- a/src/main.rs +++ b/src/main.rs @@ -147,20 +147,28 @@ fn set_working_dir(opts: &Opts) -> Result<()> { /// Detect if the user accidentally supplied a path instead of a search pattern fn ensure_search_pattern_is_not_a_path(opts: &Opts) -> Result<()> { - if !opts.full_path - && opts.pattern.contains(std::path::MAIN_SEPARATOR) - && Path::new(&opts.pattern).is_dir() - { - Err(anyhow!( + if !opts.full_path && opts.pattern.contains(std::path::MAIN_SEPARATOR) { + let is_dir = Path::new(&opts.pattern).is_dir(); + let mut message = format!( "The search pattern '{pattern}' contains a path-separation character ('{sep}') \ - and will not lead to any search results.\n\n\ - If you want to search for all files inside the '{pattern}' directory, use a match-all pattern:\n\n \ - fd . '{pattern}'\n\n\ - Instead, if you want your pattern to match the full file path, use:\n\n \ - fd --full-path '{pattern}'", + and will not lead to any search results.\n\n", pattern = &opts.pattern, sep = std::path::MAIN_SEPARATOR, - )) + ); + if is_dir { + message += &format!( + "If you want to search for all files inside the '{pattern}' directory, \ + use a match-all pattern:\n\n \ + fd . '{pattern}'\n\n", + pattern = &opts.pattern, + ); + } + message += &format!( + "If you want your pattern to match the full file path, use:\n\n \ + fd --full-path '{pattern}'", + pattern = &opts.pattern, + ); + Err(anyhow!(message)) } else { Ok(()) } diff --git a/tests/tests.rs b/tests/tests.rs index c125d3a59..664110de3 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -374,6 +374,32 @@ fn test_multi_file_with_missing() { ); } +/// Pattern containing path separator should always produce an error, +/// not only when the pattern is an existing directory. +/// Regression test for https://github.com/sharkdp/fd/issues/1873 +#[test] +fn test_path_separator_in_pattern_non_directory() { + let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES); + + // A pattern with '/' that is NOT an existing directory should still error + te.assert_failure_with_error( + &["foo/bar"], + "[fd error]: The search pattern 'foo/bar' contains a path-separation character ('/') and will not lead to any search results.", + ); +} + +#[test] +fn test_path_separator_in_pattern_existing_directory() { + let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES); + + // A pattern with '/' that IS an existing directory should also error + // and include the directory-specific hint + te.assert_failure_with_error( + &["one/two"], + "[fd error]: The search pattern 'one/two' contains a path-separation character ('/') and will not lead to any search results.", + ); +} + /// Explicit root path #[test] fn test_explicit_root_path() {