1
0
mirror of https://github.com/BurntSushi/ripgrep.git synced 2025-01-03 05:10:12 +02:00

printer: clean-up

Like a previous commit did for the grep-cli crate, this does some
polishing to the grep-printer crate. We aren't able to achieve as much
as we did with grep-cli, but we at least eliminate all rust-analyzer
lints and group imports in the way I've been doing recently.

Next we'll start doing some more invasive changes.
This commit is contained in:
Andrew Gallant 2023-09-21 16:57:02 -04:00
parent 25a7145c79
commit 09905560ff
13 changed files with 291 additions and 258 deletions

5
Cargo.lock generated
View File

@ -19,9 +19,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
version = "0.20.0"
version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5"
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
[[package]]
name = "bitflags"
@ -220,7 +220,6 @@ dependencies = [
"grep-matcher",
"grep-regex",
"grep-searcher",
"lazy_static",
"serde",
"serde_json",
"termcolor",

View File

@ -12,22 +12,33 @@ repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/printer"
readme = "README.md"
keywords = ["grep", "pattern", "print", "printer", "sink"]
license = "Unlicense OR MIT"
edition = "2018"
edition = "2021"
[features]
default = ["serde1"]
serde1 = ["base64", "serde", "serde_json"]
default = ["serde"]
serde = ["dep:base64", "dep:serde", "dep:serde_json"]
[dependencies]
base64 = { version = "0.20.0", optional = true }
bstr = "1.6.0"
base64 = { version = "0.21.4", optional = true }
bstr = "1.6.2"
gethostname = "0.4.3"
grep-matcher = { version = "0.1.6", path = "../matcher" }
grep-searcher = { version = "0.1.11", path = "../searcher" }
lazy_static = "1.1.0"
termcolor = "1.0.4"
serde = { version = "1.0.77", optional = true, features = ["derive"] }
serde_json = { version = "1.0.27", optional = true }
termcolor = "1.3.0"
serde = { version = "1.0.188", optional = true, features = ["derive"] }
serde_json = { version = "1.0.107", optional = true }
[dev-dependencies]
grep-regex = { version = "0.1.11", path = "../regex" }
[package.metadata.docs.rs]
# We want to document all features.
all-features = true
# This opts into a nightly unstable option to show the features that need to be
# enabled for public API items. To do that, we set 'docsrs', and when that's
# enabled, we enable the 'doc_auto_cfg' feature.
#
# To test this locally, run:
#
# RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features
rustdoc-args = ["--cfg", "docsrs"]

View File

@ -1,7 +1,3 @@
use std::error;
use std::fmt;
use std::str::FromStr;
use termcolor::{Color, ColorSpec, ParseColorError};
/// Returns a default set of color specifications.
@ -38,17 +34,7 @@ pub enum ColorError {
InvalidFormat(String),
}
impl error::Error for ColorError {
fn description(&self) -> &str {
match *self {
ColorError::UnrecognizedOutType(_) => "unrecognized output type",
ColorError::UnrecognizedSpecType(_) => "unrecognized spec type",
ColorError::UnrecognizedColor(_, _) => "unrecognized color name",
ColorError::UnrecognizedStyle(_) => "unrecognized style attribute",
ColorError::InvalidFormat(_) => "invalid color spec",
}
}
}
impl std::error::Error for ColorError {}
impl ColorError {
fn from_parse_error(err: ParseColorError) -> ColorError {
@ -59,33 +45,33 @@ impl ColorError {
}
}
impl fmt::Display for ColorError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl std::fmt::Display for ColorError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
ColorError::UnrecognizedOutType(ref name) => write!(
f,
"unrecognized output type '{}'. Choose from: \
path, line, column, match.",
path, line, column, match.",
name,
),
ColorError::UnrecognizedSpecType(ref name) => write!(
f,
"unrecognized spec type '{}'. Choose from: \
fg, bg, style, none.",
fg, bg, style, none.",
name,
),
ColorError::UnrecognizedColor(_, ref msg) => write!(f, "{}", msg),
ColorError::UnrecognizedStyle(ref name) => write!(
f,
"unrecognized style attribute '{}'. Choose from: \
nobold, bold, nointense, intense, nounderline, \
underline.",
nobold, bold, nointense, intense, nounderline, \
underline.",
name,
),
ColorError::InvalidFormat(ref original) => write!(
f,
"invalid color spec format: '{}'. Valid format \
is '(path|line|column|match):(fg|bg|style):(value)'.",
is '(path|line|column|match):(fg|bg|style):(value)'.",
original,
),
}
@ -305,7 +291,7 @@ impl SpecValue {
}
}
impl FromStr for UserColorSpec {
impl std::str::FromStr for UserColorSpec {
type Err = ColorError;
fn from_str(s: &str) -> Result<UserColorSpec, ColorError> {
@ -345,7 +331,7 @@ impl FromStr for UserColorSpec {
}
}
impl FromStr for OutType {
impl std::str::FromStr for OutType {
type Err = ColorError;
fn from_str(s: &str) -> Result<OutType, ColorError> {
@ -359,7 +345,7 @@ impl FromStr for OutType {
}
}
impl FromStr for SpecType {
impl std::str::FromStr for SpecType {
type Err = ColorError;
fn from_str(s: &str) -> Result<SpecType, ColorError> {
@ -373,7 +359,7 @@ impl FromStr for SpecType {
}
}
impl FromStr for Style {
impl std::str::FromStr for Style {
type Err = ColorError;
fn from_str(s: &str) -> Result<Style, ColorError> {

View File

@ -5,32 +5,32 @@ use termcolor::{ColorSpec, HyperlinkSpec, WriteColor};
/// A writer that counts the number of bytes that have been successfully
/// written.
#[derive(Clone, Debug)]
pub struct CounterWriter<W> {
pub(crate) struct CounterWriter<W> {
wtr: W,
count: u64,
total_count: u64,
}
impl<W: Write> CounterWriter<W> {
pub fn new(wtr: W) -> CounterWriter<W> {
CounterWriter { wtr: wtr, count: 0, total_count: 0 }
pub(crate) fn new(wtr: W) -> CounterWriter<W> {
CounterWriter { wtr, count: 0, total_count: 0 }
}
}
impl<W> CounterWriter<W> {
/// Returns the total number of bytes written since construction or the
/// last time `reset` was called.
pub fn count(&self) -> u64 {
pub(crate) fn count(&self) -> u64 {
self.count
}
/// Returns the total number of bytes written since construction.
pub fn total_count(&self) -> u64 {
pub(crate) fn total_count(&self) -> u64 {
self.total_count + self.count
}
/// Resets the number of bytes written to `0`.
pub fn reset_count(&mut self) {
pub(crate) fn reset_count(&mut self) {
self.total_count += self.count;
self.count = 0;
}
@ -40,21 +40,21 @@ impl<W> CounterWriter<W> {
/// After this call, the total count of bytes written to the underlying
/// writer is erased and reset.
#[allow(dead_code)]
pub fn clear(&mut self) {
pub(crate) fn clear(&mut self) {
self.count = 0;
self.total_count = 0;
}
#[allow(dead_code)]
pub fn get_ref(&self) -> &W {
pub(crate) fn get_ref(&self) -> &W {
&self.wtr
}
pub fn get_mut(&mut self) -> &mut W {
pub(crate) fn get_mut(&mut self) -> &mut W {
&mut self.wtr
}
pub fn into_inner(self) -> W {
pub(crate) fn into_inner(self) -> W {
self.wtr
}
}

View File

@ -1,12 +1,14 @@
use std::{
io::{self, Write},
path::Path,
};
use {
bstr::ByteSlice,
termcolor::{HyperlinkSpec, WriteColor},
};
use crate::hyperlink_aliases::HYPERLINK_PATTERN_ALIASES;
use bstr::ByteSlice;
use std::error::Error;
use std::fmt::Display;
use std::io;
use std::io::Write;
use std::path::Path;
use std::str::FromStr;
use termcolor::{HyperlinkSpec, WriteColor};
/// A builder for `HyperlinkPattern`.
///
@ -65,7 +67,8 @@ pub struct HyperlinkValues<'a> {
/// Represents the {file} part of a hyperlink.
///
/// This is the value to use as-is in the hyperlink, converted from an OS file path.
/// This is the value to use as-is in the hyperlink, converted from an OS file
/// path.
#[derive(Clone, Debug)]
pub struct HyperlinkPath(Vec<u8>);
@ -231,7 +234,7 @@ impl HyperlinkPattern {
}
}
impl FromStr for HyperlinkPattern {
impl std::str::FromStr for HyperlinkPattern {
type Err = HyperlinkPatternError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
@ -308,24 +311,31 @@ impl ToString for Part {
}
}
impl Display for HyperlinkPatternError {
impl std::fmt::Display for HyperlinkPatternError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HyperlinkPatternError::InvalidSyntax => {
write!(f, "invalid hyperlink pattern syntax")
}
HyperlinkPatternError::NoFilePlaceholder => {
write!(f, "the {{file}} placeholder is required in hyperlink patterns")
write!(
f,
"the {{file}} placeholder is required in hyperlink \
patterns",
)
}
HyperlinkPatternError::NoLinePlaceholder => {
write!(f, "the hyperlink pattern contains a {{column}} placeholder, \
but no {{line}} placeholder is present")
write!(
f,
"the hyperlink pattern contains a {{column}} placeholder, \
but no {{line}} placeholder is present",
)
}
HyperlinkPatternError::InvalidPlaceholder(name) => {
write!(
f,
"invalid hyperlink pattern placeholder: '{}', choose from: \
file, line, column, host",
"invalid hyperlink pattern placeholder: '{}', choose \
from: file, line, column, host",
name
)
}
@ -339,7 +349,7 @@ impl Display for HyperlinkPatternError {
}
}
impl Error for HyperlinkPatternError {}
impl std::error::Error for HyperlinkPatternError {}
impl<'a> HyperlinkValues<'a> {
/// Creates a new set of hyperlink values.
@ -360,8 +370,9 @@ impl HyperlinkPath {
/// Returns a hyperlink path from an OS path.
#[cfg(unix)]
pub fn from_path(path: &Path) -> Option<Self> {
// On Unix, this function returns the absolute file path without the leading slash,
// as it makes for more natural hyperlink patterns, for instance:
// On Unix, this function returns the absolute file path without the
// leading slash, as it makes for more natural hyperlink patterns, for
// instance:
// file://{host}/{file} instead of file://{host}{file}
// vscode://file/{file} instead of vscode://file{file}
// It also allows for patterns to be multi-platform.
@ -410,11 +421,12 @@ impl HyperlinkPath {
// Also note that the file://C:/dir/file.txt syntax is not correct,
// even though it often works in practice.
//
// In the end, this choice was confirmed by VSCode, whose pattern
// is vscode://file/{file}:{line}:{column} and which correctly understands
// In the end, this choice was confirmed by VSCode, whose pattern is
// vscode://file/{file}:{line}:{column} and which correctly understands
// the following URL format for network drives:
// vscode://file//server/dir/file.txt:1:1
// It doesn't parse any other number of slashes in "file//server" as a network path.
// It doesn't parse any other number of slashes in "file//server" as a
// network path.
const WIN32_NAMESPACE_PREFIX: &[u8] = br"\\?\";
const UNC_PREFIX: &[u8] = br"UNC\";
@ -438,14 +450,15 @@ impl HyperlinkPath {
/// Percent-encodes a path.
///
/// The alphanumeric ASCII characters and "-", ".", "_", "~" are unreserved
/// as per section 2.3 of RFC 3986 (Uniform Resource Identifier (URI): Generic Syntax),
/// and are not encoded. The other ASCII characters except "/" and ":" are percent-encoded,
/// and "\" is replaced by "/" on Windows.
/// as per section 2.3 of RFC 3986 (Uniform Resource Identifier (URI):
/// Generic Syntax), and are not encoded. The other ASCII characters except
/// "/" and ":" are percent-encoded, and "\" is replaced by "/" on Windows.
///
/// Section 4 of RFC 8089 (The "file" URI Scheme) does not mandate precise encoding
/// requirements for non-ASCII characters, and this implementation leaves them unencoded.
/// On Windows, the UrlCreateFromPathW function does not encode non-ASCII characters.
/// Doing so with UTF-8 encoded paths creates invalid file:// URLs on that platform.
/// Section 4 of RFC 8089 (The "file" URI Scheme) does not mandate precise
/// encoding requirements for non-ASCII characters, and this implementation
/// leaves them unencoded. On Windows, the UrlCreateFromPathW function does
/// not encode non-ASCII characters. Doing so with UTF-8 encoded paths
/// creates invalid file:// URLs on that platform.
fn encode(input: &[u8]) -> HyperlinkPath {
let mut result = Vec::with_capacity(input.len());
@ -480,7 +493,7 @@ impl HyperlinkPath {
}
}
impl Display for HyperlinkPath {
impl std::fmt::Display for HyperlinkPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
@ -490,15 +503,16 @@ impl Display for HyperlinkPath {
}
}
/// A simple abstraction over a hyperlink span written to the terminal.
/// This helps tracking whether a hyperlink has been started, and should be ended.
/// A simple abstraction over a hyperlink span written to the terminal. This
/// helps tracking whether a hyperlink has been started, and should be ended.
#[derive(Debug, Default)]
pub struct HyperlinkSpan {
active: bool,
}
impl HyperlinkSpan {
/// Starts a hyperlink and returns a span which tracks whether it is still in effect.
/// Starts a hyperlink and returns a span which tracks whether it is still
/// in effect.
pub fn start(
wtr: &mut impl WriteColor,
hyperlink: &HyperlinkSpec,
@ -528,6 +542,8 @@ impl HyperlinkSpan {
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::*;
#[test]
@ -653,7 +669,8 @@ mod tests {
for name in names {
assert!(
name > previous_name,
r#""{}" should be sorted before "{}" in `HYPERLINK_PATTERN_ALIASES`"#,
"'{}' should be sorted before '{}' \
in HYPERLINK_PATTERN_ALIASES",
name,
previous_name
);

View File

@ -1,7 +1,7 @@
/// Aliases to well-known hyperlink schemes.
///
/// These need to be sorted by name.
pub const HYPERLINK_PATTERN_ALIASES: &[(&str, &str)] = &[
pub(crate) const HYPERLINK_PATTERN_ALIASES: &[(&str, &str)] = &[
#[cfg(unix)]
("file", "file://{host}/{file}"),
#[cfg(windows)]

View File

@ -1,17 +1,20 @@
use std::io::{self, Write};
use std::path::Path;
use std::time::Instant;
use grep_matcher::{Match, Matcher};
use grep_searcher::{
Searcher, Sink, SinkContext, SinkContextKind, SinkFinish, SinkMatch,
use std::{
io::{self, Write},
path::Path,
time::Instant,
};
use serde_json as json;
use crate::counter::CounterWriter;
use crate::jsont;
use crate::stats::Stats;
use crate::util::find_iter_at_in_context;
use {
grep_matcher::{Match, Matcher},
grep_searcher::{
Searcher, Sink, SinkContext, SinkContextKind, SinkFinish, SinkMatch,
},
serde_json as json,
};
use crate::{
counter::CounterWriter, jsont, stats::Stats, util::find_iter_at_in_context,
};
/// The configuration for the JSON printer.
///
@ -467,7 +470,7 @@ impl<W: io::Write> JSON<W> {
matcher: M,
) -> JSONSink<'static, 's, M, W> {
JSONSink {
matcher: matcher,
matcher,
json: self,
path: None,
start_time: Instant::now(),
@ -493,7 +496,7 @@ impl<W: io::Write> JSON<W> {
P: ?Sized + AsRef<Path>,
{
JSONSink {
matcher: matcher,
matcher,
json: self,
path: Some(path.as_ref()),
start_time: Instant::now(),

View File

@ -6,19 +6,19 @@
// convenient for deserialization however, so these types would become a bit
// more complex.
use std::borrow::Cow;
use std::path::Path;
use std::str;
use std::{borrow::Cow, path::Path};
use base64;
use serde::{Serialize, Serializer};
use {
base64,
serde::{Serialize, Serializer},
};
use crate::stats::Stats;
#[derive(Serialize)]
#[serde(tag = "type", content = "data")]
#[serde(rename_all = "snake_case")]
pub enum Message<'a> {
pub(crate) enum Message<'a> {
Begin(Begin<'a>),
End(End<'a>),
Match(Match<'a>),
@ -26,48 +26,48 @@ pub enum Message<'a> {
}
#[derive(Serialize)]
pub struct Begin<'a> {
pub(crate) struct Begin<'a> {
#[serde(serialize_with = "ser_path")]
pub path: Option<&'a Path>,
pub(crate) path: Option<&'a Path>,
}
#[derive(Serialize)]
pub struct End<'a> {
pub(crate) struct End<'a> {
#[serde(serialize_with = "ser_path")]
pub path: Option<&'a Path>,
pub binary_offset: Option<u64>,
pub stats: Stats,
pub(crate) path: Option<&'a Path>,
pub(crate) binary_offset: Option<u64>,
pub(crate) stats: Stats,
}
#[derive(Serialize)]
pub struct Match<'a> {
pub(crate) struct Match<'a> {
#[serde(serialize_with = "ser_path")]
pub path: Option<&'a Path>,
pub(crate) path: Option<&'a Path>,
#[serde(serialize_with = "ser_bytes")]
pub lines: &'a [u8],
pub line_number: Option<u64>,
pub absolute_offset: u64,
pub submatches: &'a [SubMatch<'a>],
pub(crate) lines: &'a [u8],
pub(crate) line_number: Option<u64>,
pub(crate) absolute_offset: u64,
pub(crate) submatches: &'a [SubMatch<'a>],
}
#[derive(Serialize)]
pub struct Context<'a> {
pub(crate) struct Context<'a> {
#[serde(serialize_with = "ser_path")]
pub path: Option<&'a Path>,
pub(crate) path: Option<&'a Path>,
#[serde(serialize_with = "ser_bytes")]
pub lines: &'a [u8],
pub line_number: Option<u64>,
pub absolute_offset: u64,
pub submatches: &'a [SubMatch<'a>],
pub(crate) lines: &'a [u8],
pub(crate) line_number: Option<u64>,
pub(crate) absolute_offset: u64,
pub(crate) submatches: &'a [SubMatch<'a>],
}
#[derive(Serialize)]
pub struct SubMatch<'a> {
pub(crate) struct SubMatch<'a> {
#[serde(rename = "match")]
#[serde(serialize_with = "ser_bytes")]
pub m: &'a [u8],
pub start: usize,
pub end: usize,
pub(crate) m: &'a [u8],
pub(crate) start: usize,
pub(crate) end: usize,
}
/// Data represents things that look like strings, but may actually not be
@ -91,7 +91,7 @@ enum Data<'a> {
impl<'a> Data<'a> {
fn from_bytes(bytes: &[u8]) -> Data<'_> {
match str::from_utf8(bytes) {
match std::str::from_utf8(bytes) {
Ok(text) => Data::Text { text: Cow::Borrowed(text) },
Err(_) => Data::Bytes { bytes },
}
@ -123,7 +123,8 @@ where
T: AsRef<[u8]>,
S: Serializer,
{
ser.serialize_str(&base64::encode(&bytes))
use base64::engine::{general_purpose::STANDARD, Engine};
ser.serialize_str(&STANDARD.encode(&bytes))
}
fn ser_bytes<T, S>(bytes: T, ser: S) -> Result<S::Ok, S::Error>

View File

@ -27,11 +27,11 @@ contain matches.
This example shows how to create a "standard" printer and execute a search.
```
use std::error::Error;
use grep_regex::RegexMatcher;
use grep_printer::Standard;
use grep_searcher::Searcher;
use {
grep_regex::RegexMatcher,
grep_printer::Standard,
grep_searcher::Searcher,
};
const SHERLOCK: &'static [u8] = b"\
For the Doctor Watsons of this world, as opposed to the Sherlock
@ -42,41 +42,40 @@ but Doctor Watson has to have it taken out for him and dusted,
and exhibited clearly, with a label attached.
";
# fn main() { example().unwrap(); }
fn example() -> Result<(), Box<Error>> {
let matcher = RegexMatcher::new(r"Sherlock")?;
let mut printer = Standard::new_no_color(vec![]);
Searcher::new().search_slice(&matcher, SHERLOCK, printer.sink(&matcher))?;
let matcher = RegexMatcher::new(r"Sherlock")?;
let mut printer = Standard::new_no_color(vec![]);
Searcher::new().search_slice(&matcher, SHERLOCK, printer.sink(&matcher))?;
// into_inner gives us back the underlying writer we provided to
// new_no_color, which is wrapped in a termcolor::NoColor. Thus, a second
// into_inner gives us back the actual buffer.
let output = String::from_utf8(printer.into_inner().into_inner())?;
let expected = "\
// into_inner gives us back the underlying writer we provided to
// new_no_color, which is wrapped in a termcolor::NoColor. Thus, a second
// into_inner gives us back the actual buffer.
let output = String::from_utf8(printer.into_inner().into_inner())?;
let expected = "\
1:For the Doctor Watsons of this world, as opposed to the Sherlock
3:be, to a very large extent, the result of luck. Sherlock Holmes
";
assert_eq!(output, expected);
Ok(())
}
assert_eq!(output, expected);
# Ok::<(), Box<dyn std::error::Error>>(())
```
*/
#![deny(missing_docs)]
#![cfg_attr(feature = "pattern", feature(pattern))]
pub use crate::color::{
default_color_specs, ColorError, ColorSpecs, UserColorSpec,
pub use crate::{
color::{default_color_specs, ColorError, ColorSpecs, UserColorSpec},
hyperlink::{
HyperlinkPath, HyperlinkPattern, HyperlinkPatternBuilder,
HyperlinkPatternError, HyperlinkSpan, HyperlinkValues,
},
standard::{Standard, StandardBuilder, StandardSink},
stats::Stats,
summary::{Summary, SummaryBuilder, SummaryKind, SummarySink},
util::PrinterPath,
};
pub use crate::hyperlink::{
HyperlinkPath, HyperlinkPattern, HyperlinkPatternError, HyperlinkSpan,
HyperlinkValues,
};
#[cfg(feature = "serde1")]
#[cfg(feature = "serde")]
pub use crate::json::{JSONBuilder, JSONSink, JSON};
pub use crate::standard::{Standard, StandardBuilder, StandardSink};
pub use crate::stats::Stats;
pub use crate::summary::{Summary, SummaryBuilder, SummaryKind, SummarySink};
pub use crate::util::PrinterPath;
// The maximum number of bytes to execute a search to account for look-ahead.
//
@ -96,9 +95,9 @@ mod color;
mod counter;
mod hyperlink;
mod hyperlink_aliases;
#[cfg(feature = "serde1")]
#[cfg(feature = "serde")]
mod json;
#[cfg(feature = "serde1")]
#[cfg(feature = "serde")]
mod jsont;
mod standard;
mod stats;

View File

@ -1,25 +1,31 @@
use std::cell::{Cell, RefCell};
use std::cmp;
use std::io::{self, Write};
use std::path::Path;
use std::sync::Arc;
use std::time::Instant;
use bstr::ByteSlice;
use grep_matcher::{Match, Matcher};
use grep_searcher::{
LineStep, Searcher, Sink, SinkContext, SinkContextKind, SinkFinish,
SinkMatch,
use std::{
cell::{Cell, RefCell},
cmp,
io::{self, Write},
path::Path,
sync::Arc,
time::Instant,
};
use termcolor::{ColorSpec, NoColor, WriteColor};
use crate::color::ColorSpecs;
use crate::counter::CounterWriter;
use crate::hyperlink::{HyperlinkPattern, HyperlinkSpan};
use crate::stats::Stats;
use crate::util::{
find_iter_at_in_context, trim_ascii_prefix, trim_line_terminator,
PrinterPath, Replacer, Sunk,
use {
bstr::ByteSlice,
grep_matcher::{Match, Matcher},
grep_searcher::{
LineStep, Searcher, Sink, SinkContext, SinkContextKind, SinkFinish,
SinkMatch,
},
termcolor::{ColorSpec, NoColor, WriteColor},
};
use crate::{
color::ColorSpecs,
counter::CounterWriter,
hyperlink::{HyperlinkPattern, HyperlinkSpan},
stats::Stats,
util::{
find_iter_at_in_context, trim_ascii_prefix, trim_line_terminator,
PrinterPath, Replacer, Sunk,
},
};
/// The configuration for the standard printer.
@ -522,7 +528,7 @@ impl<W: WriteColor> Standard<W> {
let stats = if self.config.stats { Some(Stats::new()) } else { None };
let needs_match_granularity = self.needs_match_granularity();
StandardSink {
matcher: matcher,
matcher,
standard: self,
replacer: Replacer::new(),
path: None,
@ -530,8 +536,8 @@ impl<W: WriteColor> Standard<W> {
match_count: 0,
after_context_remaining: 0,
binary_byte_offset: None,
stats: stats,
needs_match_granularity: needs_match_granularity,
stats,
needs_match_granularity,
}
}
@ -558,7 +564,7 @@ impl<W: WriteColor> Standard<W> {
);
let needs_match_granularity = self.needs_match_granularity();
StandardSink {
matcher: matcher,
matcher,
standard: self,
replacer: Replacer::new(),
path: Some(ppath),
@ -566,8 +572,8 @@ impl<W: WriteColor> Standard<W> {
match_count: 0,
after_context_remaining: 0,
binary_byte_offset: None,
stats: stats,
needs_match_granularity: needs_match_granularity,
stats,
needs_match_granularity,
}
}
@ -935,8 +941,8 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
sink: &'a StandardSink<'_, '_, M, W>,
) -> StandardImpl<'a, M, W> {
StandardImpl {
searcher: searcher,
sink: sink,
searcher,
sink,
sunk: Sunk::empty(),
in_color_match: Cell::new(false),
}
@ -954,7 +960,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
&sink.standard.matches,
sink.replacer.replacement(),
);
StandardImpl { sunk: sunk, ..StandardImpl::new(searcher, sink) }
StandardImpl { sunk, ..StandardImpl::new(searcher, sink) }
}
/// Bundle self with a searcher and return the core implementation of Sink
@ -969,7 +975,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
&sink.standard.matches,
sink.replacer.replacement(),
);
StandardImpl { sunk: sunk, ..StandardImpl::new(searcher, sink) }
StandardImpl { sunk, ..StandardImpl::new(searcher, sink) }
}
fn sink(&self) -> io::Result<()> {
@ -1657,9 +1663,10 @@ impl<'a, M: Matcher, W: WriteColor> PreludeWriter<'a, M, W> {
/// Starts the prelude with a hyperlink when applicable.
///
/// If a heading was written, and the hyperlink pattern is invariant on the line number,
/// then this doesn't hyperlink each line prelude, as it wouldn't point to the line anyway.
/// The hyperlink on the heading should be sufficient and less confusing.
/// If a heading was written, and the hyperlink pattern is invariant on
/// the line number, then this doesn't hyperlink each line prelude, as it
/// wouldn't point to the line anyway. The hyperlink on the heading should
/// be sufficient and less confusing.
fn start(
&mut self,
line_number: Option<u64>,

View File

@ -1,5 +1,7 @@
use std::ops::{Add, AddAssign};
use std::time::Duration;
use std::{
ops::{Add, AddAssign},
time::Duration,
};
use crate::util::NiceDuration;
@ -8,7 +10,7 @@ use crate::util::NiceDuration;
/// When statistics are reported by a printer, they correspond to all searches
/// executed with that printer.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct Stats {
elapsed: NiceDuration,
searches: u64,

View File

@ -1,18 +1,24 @@
use std::cell::RefCell;
use std::io::{self, Write};
use std::path::Path;
use std::sync::Arc;
use std::time::Instant;
use std::{
cell::RefCell,
io::{self, Write},
path::Path,
sync::Arc,
time::Instant,
};
use grep_matcher::Matcher;
use grep_searcher::{Searcher, Sink, SinkError, SinkFinish, SinkMatch};
use termcolor::{ColorSpec, NoColor, WriteColor};
use {
grep_matcher::Matcher,
grep_searcher::{Searcher, Sink, SinkError, SinkFinish, SinkMatch},
termcolor::{ColorSpec, NoColor, WriteColor},
};
use crate::color::ColorSpecs;
use crate::counter::CounterWriter;
use crate::hyperlink::{HyperlinkPattern, HyperlinkSpan};
use crate::stats::Stats;
use crate::util::{find_iter_at_in_context, PrinterPath};
use crate::{
color::ColorSpecs,
counter::CounterWriter,
hyperlink::{HyperlinkPattern, HyperlinkSpan},
stats::Stats,
util::{find_iter_at_in_context, PrinterPath},
};
/// The configuration for the summary printer.
///
@ -392,13 +398,13 @@ impl<W: WriteColor> Summary<W> {
None
};
SummarySink {
matcher: matcher,
matcher,
summary: self,
path: None,
start_time: Instant::now(),
match_count: 0,
binary_byte_offset: None,
stats: stats,
stats,
}
}
@ -428,13 +434,13 @@ impl<W: WriteColor> Summary<W> {
self.config.separator_path,
);
SummarySink {
matcher: matcher,
matcher,
summary: self,
path: Some(ppath),
start_time: Instant::now(),
match_count: 0,
binary_byte_offset: None,
stats: stats,
stats,
}
}
}

View File

@ -1,23 +1,24 @@
use std::borrow::Cow;
use std::cell::OnceCell;
use std::path::Path;
use std::time;
use std::{fmt, io};
use std::{borrow::Cow, fmt, io, path::Path, time};
use bstr::{ByteSlice, ByteVec};
use grep_matcher::{Captures, LineTerminator, Match, Matcher};
use grep_searcher::{
LineIter, Searcher, SinkContext, SinkContextKind, SinkError, SinkMatch,
use {
bstr::{ByteSlice, ByteVec},
grep_matcher::{Captures, LineTerminator, Match, Matcher},
grep_searcher::{
LineIter, Searcher, SinkContext, SinkContextKind, SinkError, SinkMatch,
},
termcolor::HyperlinkSpec,
};
#[cfg(feature = "serde1")]
use serde::{Serialize, Serializer};
use termcolor::HyperlinkSpec;
use crate::hyperlink::{HyperlinkPath, HyperlinkPattern, HyperlinkValues};
use crate::MAX_LOOK_AHEAD;
#[cfg(feature = "serde")]
use serde::{Serialize, Serializer};
use crate::{
hyperlink::{HyperlinkPath, HyperlinkPattern, HyperlinkValues},
MAX_LOOK_AHEAD,
};
/// A type for handling replacements while amortizing allocation.
pub struct Replacer<M: Matcher> {
pub(crate) struct Replacer<M: Matcher> {
space: Option<Space<M>>,
}
@ -45,7 +46,7 @@ impl<M: Matcher> Replacer<M> {
///
/// This constructor does not allocate. Instead, space for dealing with
/// replacements is allocated lazily only when needed.
pub fn new() -> Replacer<M> {
pub(crate) fn new() -> Replacer<M> {
Replacer { space: None }
}
@ -54,7 +55,7 @@ impl<M: Matcher> Replacer<M> {
/// replacement, use the `replacement` method.
///
/// This can fail if the underlying matcher reports an error.
pub fn replace_all<'a>(
pub(crate) fn replace_all<'a>(
&'a mut self,
searcher: &Searcher,
matcher: &M,
@ -112,7 +113,9 @@ impl<M: Matcher> Replacer<M> {
/// all replacement occurrences within the returned replacement buffer.
///
/// If no replacement has occurred then `None` is returned.
pub fn replacement<'a>(&'a self) -> Option<(&'a [u8], &'a [Match])> {
pub(crate) fn replacement<'a>(
&'a self,
) -> Option<(&'a [u8], &'a [Match])> {
match self.space {
None => None,
Some(ref space) => {
@ -129,7 +132,7 @@ impl<M: Matcher> Replacer<M> {
///
/// Subsequent calls to `replacement` after calling `clear` (but before
/// executing another replacement) will always return `None`.
pub fn clear(&mut self) {
pub(crate) fn clear(&mut self) {
if let Some(ref mut space) = self.space {
space.dst.clear();
space.matches.clear();
@ -145,8 +148,7 @@ impl<M: Matcher> Replacer<M> {
if self.space.is_none() {
let caps =
matcher.new_captures().map_err(io::Error::error_message)?;
self.space =
Some(Space { caps: caps, dst: vec![], matches: vec![] });
self.space = Some(Space { caps, dst: vec![], matches: vec![] });
}
Ok(self.space.as_mut().unwrap())
}
@ -165,7 +167,7 @@ impl<M: Matcher> Replacer<M> {
/// results of the replacement instead of the bytes reported directly by the
/// searcher.
#[derive(Debug)]
pub struct Sunk<'a> {
pub(crate) struct Sunk<'a> {
bytes: &'a [u8],
absolute_byte_offset: u64,
line_number: Option<u64>,
@ -176,7 +178,7 @@ pub struct Sunk<'a> {
impl<'a> Sunk<'a> {
#[inline]
pub fn empty() -> Sunk<'static> {
pub(crate) fn empty() -> Sunk<'static> {
Sunk {
bytes: &[],
absolute_byte_offset: 0,
@ -188,7 +190,7 @@ impl<'a> Sunk<'a> {
}
#[inline]
pub fn from_sink_match(
pub(crate) fn from_sink_match(
sunk: &'a SinkMatch<'a>,
original_matches: &'a [Match],
replacement: Option<(&'a [u8], &'a [Match])>,
@ -196,17 +198,17 @@ impl<'a> Sunk<'a> {
let (bytes, matches) =
replacement.unwrap_or_else(|| (sunk.bytes(), original_matches));
Sunk {
bytes: bytes,
bytes,
absolute_byte_offset: sunk.absolute_byte_offset(),
line_number: sunk.line_number(),
context_kind: None,
matches: matches,
original_matches: original_matches,
matches,
original_matches,
}
}
#[inline]
pub fn from_sink_context(
pub(crate) fn from_sink_context(
sunk: &'a SinkContext<'a>,
original_matches: &'a [Match],
replacement: Option<(&'a [u8], &'a [Match])>,
@ -214,47 +216,47 @@ impl<'a> Sunk<'a> {
let (bytes, matches) =
replacement.unwrap_or_else(|| (sunk.bytes(), original_matches));
Sunk {
bytes: bytes,
bytes,
absolute_byte_offset: sunk.absolute_byte_offset(),
line_number: sunk.line_number(),
context_kind: Some(sunk.kind()),
matches: matches,
original_matches: original_matches,
matches,
original_matches,
}
}
#[inline]
pub fn context_kind(&self) -> Option<&'a SinkContextKind> {
pub(crate) fn context_kind(&self) -> Option<&'a SinkContextKind> {
self.context_kind
}
#[inline]
pub fn bytes(&self) -> &'a [u8] {
pub(crate) fn bytes(&self) -> &'a [u8] {
self.bytes
}
#[inline]
pub fn matches(&self) -> &'a [Match] {
pub(crate) fn matches(&self) -> &'a [Match] {
self.matches
}
#[inline]
pub fn original_matches(&self) -> &'a [Match] {
pub(crate) fn original_matches(&self) -> &'a [Match] {
self.original_matches
}
#[inline]
pub fn lines(&self, line_term: u8) -> LineIter<'a> {
pub(crate) fn lines(&self, line_term: u8) -> LineIter<'a> {
LineIter::new(line_term, self.bytes())
}
#[inline]
pub fn absolute_byte_offset(&self) -> u64 {
pub(crate) fn absolute_byte_offset(&self) -> u64 {
self.absolute_byte_offset
}
#[inline]
pub fn line_number(&self) -> Option<u64> {
pub(crate) fn line_number(&self) -> Option<u64> {
self.line_number
}
}
@ -281,7 +283,7 @@ impl<'a> Sunk<'a> {
pub struct PrinterPath<'a> {
path: &'a Path,
bytes: Cow<'a, [u8]>,
hyperlink_path: OnceCell<Option<HyperlinkPath>>,
hyperlink_path: std::cell::OnceCell<Option<HyperlinkPath>>,
}
impl<'a> PrinterPath<'a> {
@ -290,7 +292,7 @@ impl<'a> PrinterPath<'a> {
PrinterPath {
path,
bytes: Vec::from_path_lossy(path),
hyperlink_path: OnceCell::new(),
hyperlink_path: std::cell::OnceCell::new(),
}
}
@ -331,8 +333,8 @@ impl<'a> PrinterPath<'a> {
&self.bytes
}
/// Creates a hyperlink for this path and the given line and column, using the specified
/// pattern. Uses the given buffer to store the hyperlink.
/// Creates a hyperlink for this path and the given line and column, using
/// the specified pattern. Uses the given buffer to store the hyperlink.
pub fn create_hyperlink_spec<'b>(
&self,
pattern: &HyperlinkPattern,
@ -365,7 +367,7 @@ impl<'a> PrinterPath<'a> {
/// with the Deserialize impl for std::time::Duration, since this type only
/// adds new fields.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct NiceDuration(pub time::Duration);
pub(crate) struct NiceDuration(pub time::Duration);
impl fmt::Display for NiceDuration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -383,7 +385,7 @@ impl NiceDuration {
}
}
#[cfg(feature = "serde1")]
#[cfg(feature = "serde")]
impl Serialize for NiceDuration {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeStruct;
@ -401,7 +403,7 @@ impl Serialize for NiceDuration {
///
/// This stops trimming a prefix as soon as it sees non-whitespace or a line
/// terminator.
pub fn trim_ascii_prefix(
pub(crate) fn trim_ascii_prefix(
line_term: LineTerminator,
slice: &[u8],
range: Match,
@ -422,7 +424,7 @@ pub fn trim_ascii_prefix(
range.with_start(range.start() + count)
}
pub fn find_iter_at_in_context<M, F>(
pub(crate) fn find_iter_at_in_context<M, F>(
searcher: &Searcher,
matcher: M,
mut bytes: &[u8],
@ -482,7 +484,7 @@ where
/// Given a buf and some bounds, if there is a line terminator at the end of
/// the given bounds in buf, then the bounds are trimmed to remove the line
/// terminator.
pub fn trim_line_terminator(
pub(crate) fn trim_line_terminator(
searcher: &Searcher,
buf: &[u8],
line: &mut Match,