grep_printer/
lib.rs

1/*!
2This crate provides featureful and fast printers that interoperate with the
3[`grep-searcher`](https://docs.rs/grep-searcher)
4crate.
5
6# Brief overview
7
8The [`Standard`] printer shows results in a human readable format, and is
9modeled after the formats used by standard grep-like tools. Features include,
10but are not limited to, cross platform terminal coloring, search & replace,
11multi-line result handling and reporting summary statistics.
12
13The [`JSON`] printer shows results in a machine readable format.
14To facilitate a stream of search results, the format uses [JSON
15Lines](https://jsonlines.org/) by emitting a series of messages as search
16results are found.
17
18The [`Summary`] printer shows *aggregate* results for a single search in a
19human readable format, and is modeled after similar formats found in standard
20grep-like tools. This printer is useful for showing the total number of matches
21and/or printing file paths that either contain or don't contain matches.
22
23# Example
24
25This example shows how to create a "standard" printer and execute a search.
26
27```
28use {
29    grep_regex::RegexMatcher,
30    grep_printer::Standard,
31    grep_searcher::Searcher,
32};
33
34const SHERLOCK: &'static [u8] = b"\
35For the Doctor Watsons of this world, as opposed to the Sherlock
36Holmeses, success in the province of detective work must always
37be, to a very large extent, the result of luck. Sherlock Holmes
38can extract a clew from a wisp of straw or a flake of cigar ash;
39but Doctor Watson has to have it taken out for him and dusted,
40and exhibited clearly, with a label attached.
41";
42
43let matcher = RegexMatcher::new(r"Sherlock")?;
44let mut printer = Standard::new_no_color(vec![]);
45Searcher::new().search_slice(&matcher, SHERLOCK, printer.sink(&matcher))?;
46
47// into_inner gives us back the underlying writer we provided to
48// new_no_color, which is wrapped in a termcolor::NoColor. Thus, a second
49// into_inner gives us back the actual buffer.
50let output = String::from_utf8(printer.into_inner().into_inner())?;
51let expected = "\
521:For the Doctor Watsons of this world, as opposed to the Sherlock
533:be, to a very large extent, the result of luck. Sherlock Holmes
54";
55assert_eq!(output, expected);
56# Ok::<(), Box<dyn std::error::Error>>(())
57```
58*/
59
60#![deny(missing_docs)]
61#![cfg_attr(docsrs, feature(doc_auto_cfg))]
62
63pub use crate::{
64    color::{default_color_specs, ColorError, ColorSpecs, UserColorSpec},
65    hyperlink::{
66        HyperlinkConfig, HyperlinkEnvironment, HyperlinkFormat,
67        HyperlinkFormatError,
68    },
69    path::{PathPrinter, PathPrinterBuilder},
70    standard::{Standard, StandardBuilder, StandardSink},
71    stats::Stats,
72    summary::{Summary, SummaryBuilder, SummaryKind, SummarySink},
73};
74
75#[cfg(feature = "serde")]
76pub use crate::json::{JSONBuilder, JSONSink, JSON};
77
78// The maximum number of bytes to execute a search to account for look-ahead.
79//
80// This is an unfortunate kludge since PCRE2 doesn't provide a way to search
81// a substring of some input while accounting for look-ahead. In theory, we
82// could refactor the various 'grep' interfaces to account for it, but it would
83// be a large change. So for now, we just let PCRE2 go looking a bit for a
84// match without searching the entire rest of the contents.
85//
86// Note that this kludge is only active in multi-line mode.
87const MAX_LOOK_AHEAD: usize = 128;
88
89#[macro_use]
90mod macros;
91
92mod color;
93mod counter;
94mod hyperlink;
95mod hyperlink_aliases;
96#[cfg(feature = "serde")]
97mod json;
98#[cfg(feature = "serde")]
99mod jsont;
100mod path;
101mod standard;
102mod stats;
103mod summary;
104mod util;