summaryrefslogtreecommitdiffstats
path: root/grep/examples/simplegrep.rs
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2018-08-03 17:26:22 -0400
committerAndrew Gallant <jamslam@gmail.com>2018-08-20 07:10:19 -0400
commitbb110c1ebeeda452046830b3991f705f5759da92 (patch)
treecc2b0112a3ca9b8d05cf1e953553907d71564082 /grep/examples/simplegrep.rs
parentd9ca5293569efb255608d3c601107bcfe7060f15 (diff)
ripgrep: migrate to libripgrep
This commit does the work to delete the old `grep` crate and effectively rewrite most of ripgrep core to use the new libripgrep crates. The new `grep` crate is now a facade that collects the various crates that make up libripgrep. The most complex part of ripgrep core is now arguably the translation between command line parameters and the library options, which is ultimately where we want to be.
Diffstat (limited to 'grep/examples/simplegrep.rs')
-rw-r--r--grep/examples/simplegrep.rs107
1 files changed, 107 insertions, 0 deletions
diff --git a/grep/examples/simplegrep.rs b/grep/examples/simplegrep.rs
new file mode 100644
index 00000000..fb2d4001
--- /dev/null
+++ b/grep/examples/simplegrep.rs
@@ -0,0 +1,107 @@
+extern crate atty;
+extern crate grep;
+extern crate termcolor;
+extern crate walkdir;
+
+use std::env;
+use std::error;
+use std::ffi::OsString;
+use std::path::Path;
+use std::process;
+use std::result;
+
+use grep::printer::{ColorSpecs, StandardBuilder};
+use grep::regex::RegexMatcher;
+use grep::searcher::{BinaryDetection, SearcherBuilder};
+use termcolor::{ColorChoice, StandardStream};
+use walkdir::WalkDir;
+
+macro_rules! fail {
+ ($($tt:tt)*) => {
+ return Err(From::from(format!($($tt)*)));
+ }
+}
+
+type Result<T> = result::Result<T, Box<error::Error>>;
+
+fn main() {
+ if let Err(err) = try_main() {
+ eprintln!("{}", err);
+ process::exit(1);
+ }
+}
+
+fn try_main() -> Result<()> {
+ let mut args: Vec<OsString> = env::args_os().collect();
+ if args.len() < 2 {
+ fail!("Usage: simplegrep <pattern> [<path> ...]");
+ }
+ if args.len() == 2 {
+ args.push(OsString::from("./"));
+ }
+ let pattern = match args[1].clone().into_string() {
+ Ok(pattern) => pattern,
+ Err(_) => {
+ fail!(
+ "pattern is not valid UTF-8: '{:?}'",
+ args[1].to_string_lossy()
+ );
+ }
+ };
+ search(&pattern, &args[2..])
+}
+
+fn search(pattern: &str, paths: &[OsString]) -> Result<()> {
+ let matcher = RegexMatcher::new_line_matcher(&pattern)?;
+ let mut searcher = SearcherBuilder::new()
+ .binary_detection(BinaryDetection::quit(b'\x00'))
+ .build();
+ let mut printer = StandardBuilder::new()
+ .color_specs(colors())
+ .build(StandardStream::stdout(color_choice()));
+
+ for path in paths {
+ for result in WalkDir::new(path) {
+ let dent = match result {
+ Ok(dent) => dent,
+ Err(err) => {
+ eprintln!(
+ "{}: {}",
+ err.path().unwrap_or(Path::new("error")).display(),
+ err,
+ );
+ continue;
+ }
+ };
+ if !dent.file_type().is_file() {
+ continue;
+ }
+ let result = searcher.search_path(
+ &matcher,
+ dent.path(),
+ printer.sink_with_path(&matcher, dent.path()),
+ );
+ if let Err(err) = result {
+ eprintln!("{}: {}", dent.path().display(), err);
+ }
+ }
+ }
+ Ok(())
+}
+
+fn color_choice() -> ColorChoice {
+ if atty::is(atty::Stream::Stdout) {
+ ColorChoice::Auto
+ } else {
+ ColorChoice::Never
+ }
+}
+
+fn colors() -> ColorSpecs {
+ ColorSpecs::new(&[
+ "path:fg:magenta".parse().unwrap(),
+ "line:fg:green".parse().unwrap(),
+ "match:fg:red".parse().unwrap(),
+ "match:style:bold".parse().unwrap(),
+ ])
+}