diff --git a/CHANGELOG.md b/CHANGELOG.md index e74c844d7..e322d4d55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,9 @@ Feature enhancements: * Added or improved file type filtering for Bazel, dvc, FlatBuffers, Futhark, minified files, Mint, pofiles (from GNU gettext) Racket, VCL, Yang -* [PR #1856](https://github.com/BurntSushi/ripgrep/pull/1856): +* [FEATURE #1404](https://github.com/BurntSushi/ripgrep/pull/1404): + ripgrep now prints a warning if nothing is searched. +* [FEATURE #1856](https://github.com/BurntSushi/ripgrep/pull/1856): The README now links to a [Spanish translation](https://github.com/UltiRequiem/traducciones/tree/master/ripgrep). diff --git a/crates/core/main.rs b/crates/core/main.rs index 5a8a5eb42..18b54ec3f 100644 --- a/crates/core/main.rs +++ b/crates/core/main.rs @@ -83,12 +83,14 @@ fn search(args: &Args) -> Result { let mut stats = args.stats()?; let mut searcher = args.search_worker(args.stdout())?; let mut matched = false; + let mut searched = false; for result in args.walker()? { let subject = match subject_builder.build_from_result(result) { Some(subject) => subject, None => continue, }; + searched = true; let search_result = match searcher.search(&subject) { Ok(search_result) => search_result, Err(err) => { @@ -108,6 +110,9 @@ fn search(args: &Args) -> Result { break; } } + if !searched { + eprint_nothing_searched(); + } if let Some(ref stats) = stats { let elapsed = Instant::now().duration_since(started_at); // We don't care if we couldn't print this successfully. @@ -129,11 +134,13 @@ fn search_parallel(args: &Args) -> Result { let bufwtr = args.buffer_writer()?; let stats = args.stats()?.map(Mutex::new); let matched = AtomicBool::new(false); + let searched = AtomicBool::new(false); let mut searcher_err = None; args.walker_parallel()?.run(|| { let bufwtr = &bufwtr; let stats = &stats; let matched = &matched; + let searched = &searched; let subject_builder = &subject_builder; let mut searcher = match args.search_worker(bufwtr.buffer()) { Ok(searcher) => searcher, @@ -148,6 +155,7 @@ fn search_parallel(args: &Args) -> Result { Some(subject) => subject, None => return WalkState::Continue, }; + searched.store(true, SeqCst); searcher.printer().get_mut().clear(); let search_result = match searcher.search(&subject) { Ok(search_result) => search_result, @@ -181,6 +189,9 @@ fn search_parallel(args: &Args) -> Result { if let Some(err) = searcher_err.take() { return Err(err); } + if !searched.load(SeqCst) { + eprint_nothing_searched(); + } if let Some(ref locked_stats) = stats { let elapsed = Instant::now().duration_since(started_at); let stats = locked_stats.lock().unwrap(); @@ -191,6 +202,14 @@ fn search_parallel(args: &Args) -> Result { Ok(matched.load(SeqCst)) } +fn eprint_nothing_searched() { + err_message!( + "No files were searched, which means ripgrep probably \ + applied a filter you didn't expect.\n\ + Running with --debug will show why files are being skipped." + ); +} + /// The top-level entry point for listing files without searching them. This /// recursively steps through the file list (current directory by default) and /// prints each path sequentially using a single thread. diff --git a/tests/feature.rs b/tests/feature.rs index e140fdfe1..3cae70754 100644 --- a/tests/feature.rs +++ b/tests/feature.rs @@ -787,6 +787,47 @@ rgtest!(f1466_no_ignore_files, |dir: Dir, mut cmd: TestCommand| { eqnice!("foo\n", cmd.arg("-u").stdout()); }); +// See: https://github.com/BurntSushi/ripgrep/issues/1404 +rgtest!(f1404_nothing_searched_warning, |dir: Dir, mut cmd: TestCommand| { + dir.create(".ignore", "ignored-dir/**"); + dir.create_dir("ignored-dir"); + dir.create("ignored-dir/foo", "needle"); + + // Test that, if ripgrep searches only ignored folders/files, then there + // is a non-zero exit code. + cmd.arg("needle"); + cmd.assert_err(); + + // Test that we actually get an error message that we expect. + let output = cmd.cmd().output().unwrap(); + let stderr = String::from_utf8_lossy(&output.stderr); + let expected = "\ + No files were searched, which means ripgrep probably applied \ + a filter you didn't expect.\n\ + Running with --debug will show why files are being skipped.\n\ + "; + eqnice!(expected, stderr); +}); + +// See: https://github.com/BurntSushi/ripgrep/issues/1404 +rgtest!(f1404_nothing_searched_ignored, |dir: Dir, mut cmd: TestCommand| { + dir.create(".ignore", "ignored-dir/**"); + dir.create_dir("ignored-dir"); + dir.create("ignored-dir/foo", "needle"); + + // Test that, if ripgrep searches only ignored folders/files, then there + // is a non-zero exit code. + cmd.arg("--no-messages").arg("needle"); + cmd.assert_err(); + + // But since --no-messages is given, there should not be any error message + // printed. + let output = cmd.cmd().output().unwrap(); + let stderr = String::from_utf8_lossy(&output.stderr); + let expected = ""; + eqnice!(expected, stderr); +}); + rgtest!(no_context_sep, |dir: Dir, mut cmd: TestCommand| { dir.create("test", "foo\nctx\nbar\nctx\nfoo\nctx"); cmd.args(&["-A1", "--no-context-separator", "foo", "test"]); diff --git a/tests/regression.rs b/tests/regression.rs index 6e3454f66..1c2b5c151 100644 --- a/tests/regression.rs +++ b/tests/regression.rs @@ -392,7 +392,9 @@ rgtest!(r428_color_context_path, |dir: Dir, mut cmd: TestCommand| { }); // See: https://github.com/BurntSushi/ripgrep/issues/428 -rgtest!(r428_unrecognized_style, |_: Dir, mut cmd: TestCommand| { +rgtest!(r428_unrecognized_style, |dir: Dir, mut cmd: TestCommand| { + dir.create("file.txt", "Sherlock"); + cmd.arg("--colors=match:style:").arg("Sherlock"); cmd.assert_err();