mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-05-19 09:40:22 -07: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:
parent
25a7145c79
commit
09905560ff
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -19,9 +19,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.20.0"
|
version = "0.21.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5"
|
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
@ -220,7 +220,6 @@ dependencies = [
|
|||||||
"grep-matcher",
|
"grep-matcher",
|
||||||
"grep-regex",
|
"grep-regex",
|
||||||
"grep-searcher",
|
"grep-searcher",
|
||||||
"lazy_static",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
|
@ -12,22 +12,33 @@ repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/printer"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["grep", "pattern", "print", "printer", "sink"]
|
keywords = ["grep", "pattern", "print", "printer", "sink"]
|
||||||
license = "Unlicense OR MIT"
|
license = "Unlicense OR MIT"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["serde1"]
|
default = ["serde"]
|
||||||
serde1 = ["base64", "serde", "serde_json"]
|
serde = ["dep:base64", "dep:serde", "dep:serde_json"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = { version = "0.20.0", optional = true }
|
base64 = { version = "0.21.4", optional = true }
|
||||||
bstr = "1.6.0"
|
bstr = "1.6.2"
|
||||||
gethostname = "0.4.3"
|
gethostname = "0.4.3"
|
||||||
grep-matcher = { version = "0.1.6", path = "../matcher" }
|
grep-matcher = { version = "0.1.6", path = "../matcher" }
|
||||||
grep-searcher = { version = "0.1.11", path = "../searcher" }
|
grep-searcher = { version = "0.1.11", path = "../searcher" }
|
||||||
lazy_static = "1.1.0"
|
termcolor = "1.3.0"
|
||||||
termcolor = "1.0.4"
|
serde = { version = "1.0.188", optional = true, features = ["derive"] }
|
||||||
serde = { version = "1.0.77", optional = true, features = ["derive"] }
|
serde_json = { version = "1.0.107", optional = true }
|
||||||
serde_json = { version = "1.0.27", optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
grep-regex = { version = "0.1.11", path = "../regex" }
|
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"]
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
use std::error;
|
|
||||||
use std::fmt;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use termcolor::{Color, ColorSpec, ParseColorError};
|
use termcolor::{Color, ColorSpec, ParseColorError};
|
||||||
|
|
||||||
/// Returns a default set of color specifications.
|
/// Returns a default set of color specifications.
|
||||||
@ -38,17 +34,7 @@ pub enum ColorError {
|
|||||||
InvalidFormat(String),
|
InvalidFormat(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for ColorError {
|
impl std::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 ColorError {
|
impl ColorError {
|
||||||
fn from_parse_error(err: ParseColorError) -> ColorError {
|
fn from_parse_error(err: ParseColorError) -> ColorError {
|
||||||
@ -59,8 +45,8 @@ impl ColorError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ColorError {
|
impl std::fmt::Display for ColorError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
ColorError::UnrecognizedOutType(ref name) => write!(
|
ColorError::UnrecognizedOutType(ref name) => write!(
|
||||||
f,
|
f,
|
||||||
@ -305,7 +291,7 @@ impl SpecValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for UserColorSpec {
|
impl std::str::FromStr for UserColorSpec {
|
||||||
type Err = ColorError;
|
type Err = ColorError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<UserColorSpec, 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;
|
type Err = ColorError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<OutType, 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;
|
type Err = ColorError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<SpecType, 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;
|
type Err = ColorError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Style, ColorError> {
|
fn from_str(s: &str) -> Result<Style, ColorError> {
|
||||||
|
@ -5,32 +5,32 @@ use termcolor::{ColorSpec, HyperlinkSpec, WriteColor};
|
|||||||
/// A writer that counts the number of bytes that have been successfully
|
/// A writer that counts the number of bytes that have been successfully
|
||||||
/// written.
|
/// written.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CounterWriter<W> {
|
pub(crate) struct CounterWriter<W> {
|
||||||
wtr: W,
|
wtr: W,
|
||||||
count: u64,
|
count: u64,
|
||||||
total_count: u64,
|
total_count: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Write> CounterWriter<W> {
|
impl<W: Write> CounterWriter<W> {
|
||||||
pub fn new(wtr: W) -> CounterWriter<W> {
|
pub(crate) fn new(wtr: W) -> CounterWriter<W> {
|
||||||
CounterWriter { wtr: wtr, count: 0, total_count: 0 }
|
CounterWriter { wtr, count: 0, total_count: 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W> CounterWriter<W> {
|
impl<W> CounterWriter<W> {
|
||||||
/// Returns the total number of bytes written since construction or the
|
/// Returns the total number of bytes written since construction or the
|
||||||
/// last time `reset` was called.
|
/// last time `reset` was called.
|
||||||
pub fn count(&self) -> u64 {
|
pub(crate) fn count(&self) -> u64 {
|
||||||
self.count
|
self.count
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the total number of bytes written since construction.
|
/// 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
|
self.total_count + self.count
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets the number of bytes written to `0`.
|
/// 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.total_count += self.count;
|
||||||
self.count = 0;
|
self.count = 0;
|
||||||
}
|
}
|
||||||
@ -40,21 +40,21 @@ impl<W> CounterWriter<W> {
|
|||||||
/// After this call, the total count of bytes written to the underlying
|
/// After this call, the total count of bytes written to the underlying
|
||||||
/// writer is erased and reset.
|
/// writer is erased and reset.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn clear(&mut self) {
|
pub(crate) fn clear(&mut self) {
|
||||||
self.count = 0;
|
self.count = 0;
|
||||||
self.total_count = 0;
|
self.total_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn get_ref(&self) -> &W {
|
pub(crate) fn get_ref(&self) -> &W {
|
||||||
&self.wtr
|
&self.wtr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(&mut self) -> &mut W {
|
pub(crate) fn get_mut(&mut self) -> &mut W {
|
||||||
&mut self.wtr
|
&mut self.wtr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_inner(self) -> W {
|
pub(crate) fn into_inner(self) -> W {
|
||||||
self.wtr
|
self.wtr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 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`.
|
/// A builder for `HyperlinkPattern`.
|
||||||
///
|
///
|
||||||
@ -65,7 +67,8 @@ pub struct HyperlinkValues<'a> {
|
|||||||
|
|
||||||
/// Represents the {file} part of a hyperlink.
|
/// 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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct HyperlinkPath(Vec<u8>);
|
pub struct HyperlinkPath(Vec<u8>);
|
||||||
|
|
||||||
@ -231,7 +234,7 @@ impl HyperlinkPattern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for HyperlinkPattern {
|
impl std::str::FromStr for HyperlinkPattern {
|
||||||
type Err = HyperlinkPatternError;
|
type Err = HyperlinkPatternError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
HyperlinkPatternError::InvalidSyntax => {
|
HyperlinkPatternError::InvalidSyntax => {
|
||||||
write!(f, "invalid hyperlink pattern syntax")
|
write!(f, "invalid hyperlink pattern syntax")
|
||||||
}
|
}
|
||||||
HyperlinkPatternError::NoFilePlaceholder => {
|
HyperlinkPatternError::NoFilePlaceholder => {
|
||||||
write!(f, "the {{file}} placeholder is required in hyperlink patterns")
|
write!(
|
||||||
|
f,
|
||||||
|
"the {{file}} placeholder is required in hyperlink \
|
||||||
|
patterns",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
HyperlinkPatternError::NoLinePlaceholder => {
|
HyperlinkPatternError::NoLinePlaceholder => {
|
||||||
write!(f, "the hyperlink pattern contains a {{column}} placeholder, \
|
write!(
|
||||||
but no {{line}} placeholder is present")
|
f,
|
||||||
|
"the hyperlink pattern contains a {{column}} placeholder, \
|
||||||
|
but no {{line}} placeholder is present",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
HyperlinkPatternError::InvalidPlaceholder(name) => {
|
HyperlinkPatternError::InvalidPlaceholder(name) => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"invalid hyperlink pattern placeholder: '{}', choose from: \
|
"invalid hyperlink pattern placeholder: '{}', choose \
|
||||||
file, line, column, host",
|
from: file, line, column, host",
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -339,7 +349,7 @@ impl Display for HyperlinkPatternError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for HyperlinkPatternError {}
|
impl std::error::Error for HyperlinkPatternError {}
|
||||||
|
|
||||||
impl<'a> HyperlinkValues<'a> {
|
impl<'a> HyperlinkValues<'a> {
|
||||||
/// Creates a new set of hyperlink values.
|
/// Creates a new set of hyperlink values.
|
||||||
@ -360,8 +370,9 @@ impl HyperlinkPath {
|
|||||||
/// Returns a hyperlink path from an OS path.
|
/// Returns a hyperlink path from an OS path.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn from_path(path: &Path) -> Option<Self> {
|
pub fn from_path(path: &Path) -> Option<Self> {
|
||||||
// On Unix, this function returns the absolute file path without the leading slash,
|
// On Unix, this function returns the absolute file path without the
|
||||||
// as it makes for more natural hyperlink patterns, for instance:
|
// leading slash, as it makes for more natural hyperlink patterns, for
|
||||||
|
// instance:
|
||||||
// file://{host}/{file} instead of file://{host}{file}
|
// file://{host}/{file} instead of file://{host}{file}
|
||||||
// vscode://file/{file} instead of vscode://file{file}
|
// vscode://file/{file} instead of vscode://file{file}
|
||||||
// It also allows for patterns to be multi-platform.
|
// 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,
|
// Also note that the file://C:/dir/file.txt syntax is not correct,
|
||||||
// even though it often works in practice.
|
// even though it often works in practice.
|
||||||
//
|
//
|
||||||
// In the end, this choice was confirmed by VSCode, whose pattern
|
// In the end, this choice was confirmed by VSCode, whose pattern is
|
||||||
// is vscode://file/{file}:{line}:{column} and which correctly understands
|
// vscode://file/{file}:{line}:{column} and which correctly understands
|
||||||
// the following URL format for network drives:
|
// the following URL format for network drives:
|
||||||
// vscode://file//server/dir/file.txt:1:1
|
// 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 WIN32_NAMESPACE_PREFIX: &[u8] = br"\\?\";
|
||||||
const UNC_PREFIX: &[u8] = br"UNC\";
|
const UNC_PREFIX: &[u8] = br"UNC\";
|
||||||
@ -438,14 +450,15 @@ impl HyperlinkPath {
|
|||||||
/// Percent-encodes a path.
|
/// Percent-encodes a path.
|
||||||
///
|
///
|
||||||
/// The alphanumeric ASCII characters and "-", ".", "_", "~" are unreserved
|
/// The alphanumeric ASCII characters and "-", ".", "_", "~" are unreserved
|
||||||
/// as per section 2.3 of RFC 3986 (Uniform Resource Identifier (URI): Generic Syntax),
|
/// as per section 2.3 of RFC 3986 (Uniform Resource Identifier (URI):
|
||||||
/// and are not encoded. The other ASCII characters except "/" and ":" are percent-encoded,
|
/// Generic Syntax), and are not encoded. The other ASCII characters except
|
||||||
/// and "\" is replaced by "/" on Windows.
|
/// "/" and ":" are percent-encoded, and "\" is replaced by "/" on Windows.
|
||||||
///
|
///
|
||||||
/// Section 4 of RFC 8089 (The "file" URI Scheme) does not mandate precise encoding
|
/// Section 4 of RFC 8089 (The "file" URI Scheme) does not mandate precise
|
||||||
/// requirements for non-ASCII characters, and this implementation leaves them unencoded.
|
/// encoding requirements for non-ASCII characters, and this implementation
|
||||||
/// On Windows, the UrlCreateFromPathW function does not encode non-ASCII characters.
|
/// leaves them unencoded. On Windows, the UrlCreateFromPathW function does
|
||||||
/// Doing so with UTF-8 encoded paths creates invalid file:// URLs on that platform.
|
/// not encode non-ASCII characters. Doing so with UTF-8 encoded paths
|
||||||
|
/// creates invalid file:// URLs on that platform.
|
||||||
fn encode(input: &[u8]) -> HyperlinkPath {
|
fn encode(input: &[u8]) -> HyperlinkPath {
|
||||||
let mut result = Vec::with_capacity(input.len());
|
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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -490,15 +503,16 @@ impl Display for HyperlinkPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A simple abstraction over a hyperlink span written to the terminal.
|
/// A simple abstraction over a hyperlink span written to the terminal. This
|
||||||
/// This helps tracking whether a hyperlink has been started, and should be ended.
|
/// helps tracking whether a hyperlink has been started, and should be ended.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct HyperlinkSpan {
|
pub struct HyperlinkSpan {
|
||||||
active: bool,
|
active: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HyperlinkSpan {
|
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(
|
pub fn start(
|
||||||
wtr: &mut impl WriteColor,
|
wtr: &mut impl WriteColor,
|
||||||
hyperlink: &HyperlinkSpec,
|
hyperlink: &HyperlinkSpec,
|
||||||
@ -528,6 +542,8 @@ impl HyperlinkSpan {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -653,7 +669,8 @@ mod tests {
|
|||||||
for name in names {
|
for name in names {
|
||||||
assert!(
|
assert!(
|
||||||
name > previous_name,
|
name > previous_name,
|
||||||
r#""{}" should be sorted before "{}" in `HYPERLINK_PATTERN_ALIASES`"#,
|
"'{}' should be sorted before '{}' \
|
||||||
|
in HYPERLINK_PATTERN_ALIASES",
|
||||||
name,
|
name,
|
||||||
previous_name
|
previous_name
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/// Aliases to well-known hyperlink schemes.
|
/// Aliases to well-known hyperlink schemes.
|
||||||
///
|
///
|
||||||
/// These need to be sorted by name.
|
/// These need to be sorted by name.
|
||||||
pub const HYPERLINK_PATTERN_ALIASES: &[(&str, &str)] = &[
|
pub(crate) const HYPERLINK_PATTERN_ALIASES: &[(&str, &str)] = &[
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
("file", "file://{host}/{file}"),
|
("file", "file://{host}/{file}"),
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
use std::io::{self, Write};
|
use std::{
|
||||||
use std::path::Path;
|
io::{self, Write},
|
||||||
use std::time::Instant;
|
path::Path,
|
||||||
|
time::Instant,
|
||||||
use grep_matcher::{Match, Matcher};
|
|
||||||
use grep_searcher::{
|
|
||||||
Searcher, Sink, SinkContext, SinkContextKind, SinkFinish, SinkMatch,
|
|
||||||
};
|
};
|
||||||
use serde_json as json;
|
|
||||||
|
|
||||||
use crate::counter::CounterWriter;
|
use {
|
||||||
use crate::jsont;
|
grep_matcher::{Match, Matcher},
|
||||||
use crate::stats::Stats;
|
grep_searcher::{
|
||||||
use crate::util::find_iter_at_in_context;
|
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.
|
/// The configuration for the JSON printer.
|
||||||
///
|
///
|
||||||
@ -467,7 +470,7 @@ impl<W: io::Write> JSON<W> {
|
|||||||
matcher: M,
|
matcher: M,
|
||||||
) -> JSONSink<'static, 's, M, W> {
|
) -> JSONSink<'static, 's, M, W> {
|
||||||
JSONSink {
|
JSONSink {
|
||||||
matcher: matcher,
|
matcher,
|
||||||
json: self,
|
json: self,
|
||||||
path: None,
|
path: None,
|
||||||
start_time: Instant::now(),
|
start_time: Instant::now(),
|
||||||
@ -493,7 +496,7 @@ impl<W: io::Write> JSON<W> {
|
|||||||
P: ?Sized + AsRef<Path>,
|
P: ?Sized + AsRef<Path>,
|
||||||
{
|
{
|
||||||
JSONSink {
|
JSONSink {
|
||||||
matcher: matcher,
|
matcher,
|
||||||
json: self,
|
json: self,
|
||||||
path: Some(path.as_ref()),
|
path: Some(path.as_ref()),
|
||||||
start_time: Instant::now(),
|
start_time: Instant::now(),
|
||||||
|
@ -6,19 +6,19 @@
|
|||||||
// convenient for deserialization however, so these types would become a bit
|
// convenient for deserialization however, so these types would become a bit
|
||||||
// more complex.
|
// more complex.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::{borrow::Cow, path::Path};
|
||||||
use std::path::Path;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
use base64;
|
use {
|
||||||
use serde::{Serialize, Serializer};
|
base64,
|
||||||
|
serde::{Serialize, Serializer},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::stats::Stats;
|
use crate::stats::Stats;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(tag = "type", content = "data")]
|
#[serde(tag = "type", content = "data")]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum Message<'a> {
|
pub(crate) enum Message<'a> {
|
||||||
Begin(Begin<'a>),
|
Begin(Begin<'a>),
|
||||||
End(End<'a>),
|
End(End<'a>),
|
||||||
Match(Match<'a>),
|
Match(Match<'a>),
|
||||||
@ -26,48 +26,48 @@ pub enum Message<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct Begin<'a> {
|
pub(crate) struct Begin<'a> {
|
||||||
#[serde(serialize_with = "ser_path")]
|
#[serde(serialize_with = "ser_path")]
|
||||||
pub path: Option<&'a Path>,
|
pub(crate) path: Option<&'a Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct End<'a> {
|
pub(crate) struct End<'a> {
|
||||||
#[serde(serialize_with = "ser_path")]
|
#[serde(serialize_with = "ser_path")]
|
||||||
pub path: Option<&'a Path>,
|
pub(crate) path: Option<&'a Path>,
|
||||||
pub binary_offset: Option<u64>,
|
pub(crate) binary_offset: Option<u64>,
|
||||||
pub stats: Stats,
|
pub(crate) stats: Stats,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct Match<'a> {
|
pub(crate) struct Match<'a> {
|
||||||
#[serde(serialize_with = "ser_path")]
|
#[serde(serialize_with = "ser_path")]
|
||||||
pub path: Option<&'a Path>,
|
pub(crate) path: Option<&'a Path>,
|
||||||
#[serde(serialize_with = "ser_bytes")]
|
#[serde(serialize_with = "ser_bytes")]
|
||||||
pub lines: &'a [u8],
|
pub(crate) lines: &'a [u8],
|
||||||
pub line_number: Option<u64>,
|
pub(crate) line_number: Option<u64>,
|
||||||
pub absolute_offset: u64,
|
pub(crate) absolute_offset: u64,
|
||||||
pub submatches: &'a [SubMatch<'a>],
|
pub(crate) submatches: &'a [SubMatch<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct Context<'a> {
|
pub(crate) struct Context<'a> {
|
||||||
#[serde(serialize_with = "ser_path")]
|
#[serde(serialize_with = "ser_path")]
|
||||||
pub path: Option<&'a Path>,
|
pub(crate) path: Option<&'a Path>,
|
||||||
#[serde(serialize_with = "ser_bytes")]
|
#[serde(serialize_with = "ser_bytes")]
|
||||||
pub lines: &'a [u8],
|
pub(crate) lines: &'a [u8],
|
||||||
pub line_number: Option<u64>,
|
pub(crate) line_number: Option<u64>,
|
||||||
pub absolute_offset: u64,
|
pub(crate) absolute_offset: u64,
|
||||||
pub submatches: &'a [SubMatch<'a>],
|
pub(crate) submatches: &'a [SubMatch<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct SubMatch<'a> {
|
pub(crate) struct SubMatch<'a> {
|
||||||
#[serde(rename = "match")]
|
#[serde(rename = "match")]
|
||||||
#[serde(serialize_with = "ser_bytes")]
|
#[serde(serialize_with = "ser_bytes")]
|
||||||
pub m: &'a [u8],
|
pub(crate) m: &'a [u8],
|
||||||
pub start: usize,
|
pub(crate) start: usize,
|
||||||
pub end: usize,
|
pub(crate) end: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data represents things that look like strings, but may actually not be
|
/// Data represents things that look like strings, but may actually not be
|
||||||
@ -91,7 +91,7 @@ enum Data<'a> {
|
|||||||
|
|
||||||
impl<'a> Data<'a> {
|
impl<'a> Data<'a> {
|
||||||
fn from_bytes(bytes: &[u8]) -> Data<'_> {
|
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) },
|
Ok(text) => Data::Text { text: Cow::Borrowed(text) },
|
||||||
Err(_) => Data::Bytes { bytes },
|
Err(_) => Data::Bytes { bytes },
|
||||||
}
|
}
|
||||||
@ -123,7 +123,8 @@ where
|
|||||||
T: AsRef<[u8]>,
|
T: AsRef<[u8]>,
|
||||||
S: Serializer,
|
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>
|
fn ser_bytes<T, S>(bytes: T, ser: S) -> Result<S::Ok, S::Error>
|
||||||
|
@ -27,11 +27,11 @@ contain matches.
|
|||||||
This example shows how to create a "standard" printer and execute a search.
|
This example shows how to create a "standard" printer and execute a search.
|
||||||
|
|
||||||
```
|
```
|
||||||
use std::error::Error;
|
use {
|
||||||
|
grep_regex::RegexMatcher,
|
||||||
use grep_regex::RegexMatcher;
|
grep_printer::Standard,
|
||||||
use grep_printer::Standard;
|
grep_searcher::Searcher,
|
||||||
use grep_searcher::Searcher;
|
};
|
||||||
|
|
||||||
const SHERLOCK: &'static [u8] = b"\
|
const SHERLOCK: &'static [u8] = b"\
|
||||||
For the Doctor Watsons of this world, as opposed to the Sherlock
|
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.
|
and exhibited clearly, with a label attached.
|
||||||
";
|
";
|
||||||
|
|
||||||
# fn main() { example().unwrap(); }
|
let matcher = RegexMatcher::new(r"Sherlock")?;
|
||||||
fn example() -> Result<(), Box<Error>> {
|
let mut printer = Standard::new_no_color(vec![]);
|
||||||
let matcher = RegexMatcher::new(r"Sherlock")?;
|
Searcher::new().search_slice(&matcher, SHERLOCK, printer.sink(&matcher))?;
|
||||||
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
|
// into_inner gives us back the underlying writer we provided to
|
||||||
// new_no_color, which is wrapped in a termcolor::NoColor. Thus, a second
|
// new_no_color, which is wrapped in a termcolor::NoColor. Thus, a second
|
||||||
// into_inner gives us back the actual buffer.
|
// into_inner gives us back the actual buffer.
|
||||||
let output = String::from_utf8(printer.into_inner().into_inner())?;
|
let output = String::from_utf8(printer.into_inner().into_inner())?;
|
||||||
let expected = "\
|
let expected = "\
|
||||||
1:For the Doctor Watsons of this world, as opposed to the Sherlock
|
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
|
3:be, to a very large extent, the result of luck. Sherlock Holmes
|
||||||
";
|
";
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
Ok(())
|
# Ok::<(), Box<dyn std::error::Error>>(())
|
||||||
}
|
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
#![cfg_attr(feature = "pattern", feature(pattern))]
|
||||||
|
|
||||||
pub use crate::color::{
|
pub use crate::{
|
||||||
default_color_specs, ColorError, ColorSpecs, UserColorSpec,
|
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,
|
#[cfg(feature = "serde")]
|
||||||
HyperlinkValues,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "serde1")]
|
|
||||||
pub use crate::json::{JSONBuilder, JSONSink, JSON};
|
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.
|
// The maximum number of bytes to execute a search to account for look-ahead.
|
||||||
//
|
//
|
||||||
@ -96,9 +95,9 @@ mod color;
|
|||||||
mod counter;
|
mod counter;
|
||||||
mod hyperlink;
|
mod hyperlink;
|
||||||
mod hyperlink_aliases;
|
mod hyperlink_aliases;
|
||||||
#[cfg(feature = "serde1")]
|
#[cfg(feature = "serde")]
|
||||||
mod json;
|
mod json;
|
||||||
#[cfg(feature = "serde1")]
|
#[cfg(feature = "serde")]
|
||||||
mod jsont;
|
mod jsont;
|
||||||
mod standard;
|
mod standard;
|
||||||
mod stats;
|
mod stats;
|
||||||
|
@ -1,25 +1,31 @@
|
|||||||
use std::cell::{Cell, RefCell};
|
use std::{
|
||||||
use std::cmp;
|
cell::{Cell, RefCell},
|
||||||
use std::io::{self, Write};
|
cmp,
|
||||||
use std::path::Path;
|
io::{self, Write},
|
||||||
use std::sync::Arc;
|
path::Path,
|
||||||
use std::time::Instant;
|
sync::Arc,
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
use bstr::ByteSlice;
|
use {
|
||||||
use grep_matcher::{Match, Matcher};
|
bstr::ByteSlice,
|
||||||
use grep_searcher::{
|
grep_matcher::{Match, Matcher},
|
||||||
|
grep_searcher::{
|
||||||
LineStep, Searcher, Sink, SinkContext, SinkContextKind, SinkFinish,
|
LineStep, Searcher, Sink, SinkContext, SinkContextKind, SinkFinish,
|
||||||
SinkMatch,
|
SinkMatch,
|
||||||
|
},
|
||||||
|
termcolor::{ColorSpec, NoColor, WriteColor},
|
||||||
};
|
};
|
||||||
use termcolor::{ColorSpec, NoColor, WriteColor};
|
|
||||||
|
|
||||||
use crate::color::ColorSpecs;
|
use crate::{
|
||||||
use crate::counter::CounterWriter;
|
color::ColorSpecs,
|
||||||
use crate::hyperlink::{HyperlinkPattern, HyperlinkSpan};
|
counter::CounterWriter,
|
||||||
use crate::stats::Stats;
|
hyperlink::{HyperlinkPattern, HyperlinkSpan},
|
||||||
use crate::util::{
|
stats::Stats,
|
||||||
|
util::{
|
||||||
find_iter_at_in_context, trim_ascii_prefix, trim_line_terminator,
|
find_iter_at_in_context, trim_ascii_prefix, trim_line_terminator,
|
||||||
PrinterPath, Replacer, Sunk,
|
PrinterPath, Replacer, Sunk,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The configuration for the standard printer.
|
/// 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 stats = if self.config.stats { Some(Stats::new()) } else { None };
|
||||||
let needs_match_granularity = self.needs_match_granularity();
|
let needs_match_granularity = self.needs_match_granularity();
|
||||||
StandardSink {
|
StandardSink {
|
||||||
matcher: matcher,
|
matcher,
|
||||||
standard: self,
|
standard: self,
|
||||||
replacer: Replacer::new(),
|
replacer: Replacer::new(),
|
||||||
path: None,
|
path: None,
|
||||||
@ -530,8 +536,8 @@ impl<W: WriteColor> Standard<W> {
|
|||||||
match_count: 0,
|
match_count: 0,
|
||||||
after_context_remaining: 0,
|
after_context_remaining: 0,
|
||||||
binary_byte_offset: None,
|
binary_byte_offset: None,
|
||||||
stats: stats,
|
stats,
|
||||||
needs_match_granularity: needs_match_granularity,
|
needs_match_granularity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,7 +564,7 @@ impl<W: WriteColor> Standard<W> {
|
|||||||
);
|
);
|
||||||
let needs_match_granularity = self.needs_match_granularity();
|
let needs_match_granularity = self.needs_match_granularity();
|
||||||
StandardSink {
|
StandardSink {
|
||||||
matcher: matcher,
|
matcher,
|
||||||
standard: self,
|
standard: self,
|
||||||
replacer: Replacer::new(),
|
replacer: Replacer::new(),
|
||||||
path: Some(ppath),
|
path: Some(ppath),
|
||||||
@ -566,8 +572,8 @@ impl<W: WriteColor> Standard<W> {
|
|||||||
match_count: 0,
|
match_count: 0,
|
||||||
after_context_remaining: 0,
|
after_context_remaining: 0,
|
||||||
binary_byte_offset: None,
|
binary_byte_offset: None,
|
||||||
stats: stats,
|
stats,
|
||||||
needs_match_granularity: needs_match_granularity,
|
needs_match_granularity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -935,8 +941,8 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
sink: &'a StandardSink<'_, '_, M, W>,
|
sink: &'a StandardSink<'_, '_, M, W>,
|
||||||
) -> StandardImpl<'a, M, W> {
|
) -> StandardImpl<'a, M, W> {
|
||||||
StandardImpl {
|
StandardImpl {
|
||||||
searcher: searcher,
|
searcher,
|
||||||
sink: sink,
|
sink,
|
||||||
sunk: Sunk::empty(),
|
sunk: Sunk::empty(),
|
||||||
in_color_match: Cell::new(false),
|
in_color_match: Cell::new(false),
|
||||||
}
|
}
|
||||||
@ -954,7 +960,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
&sink.standard.matches,
|
&sink.standard.matches,
|
||||||
sink.replacer.replacement(),
|
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
|
/// 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.standard.matches,
|
||||||
sink.replacer.replacement(),
|
sink.replacer.replacement(),
|
||||||
);
|
);
|
||||||
StandardImpl { sunk: sunk, ..StandardImpl::new(searcher, sink) }
|
StandardImpl { sunk, ..StandardImpl::new(searcher, sink) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sink(&self) -> io::Result<()> {
|
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.
|
/// Starts the prelude with a hyperlink when applicable.
|
||||||
///
|
///
|
||||||
/// If a heading was written, and the hyperlink pattern is invariant on the line number,
|
/// If a heading was written, and the hyperlink pattern is invariant on
|
||||||
/// then this doesn't hyperlink each line prelude, as it wouldn't point to the line anyway.
|
/// the line number, then this doesn't hyperlink each line prelude, as it
|
||||||
/// The hyperlink on the heading should be sufficient and less confusing.
|
/// wouldn't point to the line anyway. The hyperlink on the heading should
|
||||||
|
/// be sufficient and less confusing.
|
||||||
fn start(
|
fn start(
|
||||||
&mut self,
|
&mut self,
|
||||||
line_number: Option<u64>,
|
line_number: Option<u64>,
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use std::ops::{Add, AddAssign};
|
use std::{
|
||||||
use std::time::Duration;
|
ops::{Add, AddAssign},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::util::NiceDuration;
|
use crate::util::NiceDuration;
|
||||||
|
|
||||||
@ -8,7 +10,7 @@ use crate::util::NiceDuration;
|
|||||||
/// When statistics are reported by a printer, they correspond to all searches
|
/// When statistics are reported by a printer, they correspond to all searches
|
||||||
/// executed with that printer.
|
/// executed with that printer.
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "serde1", derive(serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||||
pub struct Stats {
|
pub struct Stats {
|
||||||
elapsed: NiceDuration,
|
elapsed: NiceDuration,
|
||||||
searches: u64,
|
searches: u64,
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
use std::cell::RefCell;
|
use std::{
|
||||||
use std::io::{self, Write};
|
cell::RefCell,
|
||||||
use std::path::Path;
|
io::{self, Write},
|
||||||
use std::sync::Arc;
|
path::Path,
|
||||||
use std::time::Instant;
|
sync::Arc,
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
use grep_matcher::Matcher;
|
use {
|
||||||
use grep_searcher::{Searcher, Sink, SinkError, SinkFinish, SinkMatch};
|
grep_matcher::Matcher,
|
||||||
use termcolor::{ColorSpec, NoColor, WriteColor};
|
grep_searcher::{Searcher, Sink, SinkError, SinkFinish, SinkMatch},
|
||||||
|
termcolor::{ColorSpec, NoColor, WriteColor},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::color::ColorSpecs;
|
use crate::{
|
||||||
use crate::counter::CounterWriter;
|
color::ColorSpecs,
|
||||||
use crate::hyperlink::{HyperlinkPattern, HyperlinkSpan};
|
counter::CounterWriter,
|
||||||
use crate::stats::Stats;
|
hyperlink::{HyperlinkPattern, HyperlinkSpan},
|
||||||
use crate::util::{find_iter_at_in_context, PrinterPath};
|
stats::Stats,
|
||||||
|
util::{find_iter_at_in_context, PrinterPath},
|
||||||
|
};
|
||||||
|
|
||||||
/// The configuration for the summary printer.
|
/// The configuration for the summary printer.
|
||||||
///
|
///
|
||||||
@ -392,13 +398,13 @@ impl<W: WriteColor> Summary<W> {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
SummarySink {
|
SummarySink {
|
||||||
matcher: matcher,
|
matcher,
|
||||||
summary: self,
|
summary: self,
|
||||||
path: None,
|
path: None,
|
||||||
start_time: Instant::now(),
|
start_time: Instant::now(),
|
||||||
match_count: 0,
|
match_count: 0,
|
||||||
binary_byte_offset: None,
|
binary_byte_offset: None,
|
||||||
stats: stats,
|
stats,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,13 +434,13 @@ impl<W: WriteColor> Summary<W> {
|
|||||||
self.config.separator_path,
|
self.config.separator_path,
|
||||||
);
|
);
|
||||||
SummarySink {
|
SummarySink {
|
||||||
matcher: matcher,
|
matcher,
|
||||||
summary: self,
|
summary: self,
|
||||||
path: Some(ppath),
|
path: Some(ppath),
|
||||||
start_time: Instant::now(),
|
start_time: Instant::now(),
|
||||||
match_count: 0,
|
match_count: 0,
|
||||||
binary_byte_offset: None,
|
binary_byte_offset: None,
|
||||||
stats: stats,
|
stats,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
use std::borrow::Cow;
|
use std::{borrow::Cow, fmt, io, path::Path, time};
|
||||||
use std::cell::OnceCell;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::time;
|
|
||||||
use std::{fmt, io};
|
|
||||||
|
|
||||||
use bstr::{ByteSlice, ByteVec};
|
use {
|
||||||
use grep_matcher::{Captures, LineTerminator, Match, Matcher};
|
bstr::{ByteSlice, ByteVec},
|
||||||
use grep_searcher::{
|
grep_matcher::{Captures, LineTerminator, Match, Matcher},
|
||||||
|
grep_searcher::{
|
||||||
LineIter, Searcher, SinkContext, SinkContextKind, SinkError, SinkMatch,
|
LineIter, Searcher, SinkContext, SinkContextKind, SinkError, SinkMatch,
|
||||||
|
},
|
||||||
|
termcolor::HyperlinkSpec,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "serde1")]
|
|
||||||
use serde::{Serialize, Serializer};
|
|
||||||
use termcolor::HyperlinkSpec;
|
|
||||||
|
|
||||||
use crate::hyperlink::{HyperlinkPath, HyperlinkPattern, HyperlinkValues};
|
#[cfg(feature = "serde")]
|
||||||
use crate::MAX_LOOK_AHEAD;
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
hyperlink::{HyperlinkPath, HyperlinkPattern, HyperlinkValues},
|
||||||
|
MAX_LOOK_AHEAD,
|
||||||
|
};
|
||||||
|
|
||||||
/// A type for handling replacements while amortizing allocation.
|
/// A type for handling replacements while amortizing allocation.
|
||||||
pub struct Replacer<M: Matcher> {
|
pub(crate) struct Replacer<M: Matcher> {
|
||||||
space: Option<Space<M>>,
|
space: Option<Space<M>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ impl<M: Matcher> Replacer<M> {
|
|||||||
///
|
///
|
||||||
/// This constructor does not allocate. Instead, space for dealing with
|
/// This constructor does not allocate. Instead, space for dealing with
|
||||||
/// replacements is allocated lazily only when needed.
|
/// replacements is allocated lazily only when needed.
|
||||||
pub fn new() -> Replacer<M> {
|
pub(crate) fn new() -> Replacer<M> {
|
||||||
Replacer { space: None }
|
Replacer { space: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ impl<M: Matcher> Replacer<M> {
|
|||||||
/// replacement, use the `replacement` method.
|
/// replacement, use the `replacement` method.
|
||||||
///
|
///
|
||||||
/// This can fail if the underlying matcher reports an error.
|
/// This can fail if the underlying matcher reports an error.
|
||||||
pub fn replace_all<'a>(
|
pub(crate) fn replace_all<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
searcher: &Searcher,
|
searcher: &Searcher,
|
||||||
matcher: &M,
|
matcher: &M,
|
||||||
@ -112,7 +113,9 @@ impl<M: Matcher> Replacer<M> {
|
|||||||
/// all replacement occurrences within the returned replacement buffer.
|
/// all replacement occurrences within the returned replacement buffer.
|
||||||
///
|
///
|
||||||
/// If no replacement has occurred then `None` is returned.
|
/// 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 {
|
match self.space {
|
||||||
None => None,
|
None => None,
|
||||||
Some(ref space) => {
|
Some(ref space) => {
|
||||||
@ -129,7 +132,7 @@ impl<M: Matcher> Replacer<M> {
|
|||||||
///
|
///
|
||||||
/// Subsequent calls to `replacement` after calling `clear` (but before
|
/// Subsequent calls to `replacement` after calling `clear` (but before
|
||||||
/// executing another replacement) will always return `None`.
|
/// 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 {
|
if let Some(ref mut space) = self.space {
|
||||||
space.dst.clear();
|
space.dst.clear();
|
||||||
space.matches.clear();
|
space.matches.clear();
|
||||||
@ -145,8 +148,7 @@ impl<M: Matcher> Replacer<M> {
|
|||||||
if self.space.is_none() {
|
if self.space.is_none() {
|
||||||
let caps =
|
let caps =
|
||||||
matcher.new_captures().map_err(io::Error::error_message)?;
|
matcher.new_captures().map_err(io::Error::error_message)?;
|
||||||
self.space =
|
self.space = Some(Space { caps, dst: vec![], matches: vec![] });
|
||||||
Some(Space { caps: caps, dst: vec![], matches: vec![] });
|
|
||||||
}
|
}
|
||||||
Ok(self.space.as_mut().unwrap())
|
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
|
/// results of the replacement instead of the bytes reported directly by the
|
||||||
/// searcher.
|
/// searcher.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Sunk<'a> {
|
pub(crate) struct Sunk<'a> {
|
||||||
bytes: &'a [u8],
|
bytes: &'a [u8],
|
||||||
absolute_byte_offset: u64,
|
absolute_byte_offset: u64,
|
||||||
line_number: Option<u64>,
|
line_number: Option<u64>,
|
||||||
@ -176,7 +178,7 @@ pub struct Sunk<'a> {
|
|||||||
|
|
||||||
impl<'a> Sunk<'a> {
|
impl<'a> Sunk<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn empty() -> Sunk<'static> {
|
pub(crate) fn empty() -> Sunk<'static> {
|
||||||
Sunk {
|
Sunk {
|
||||||
bytes: &[],
|
bytes: &[],
|
||||||
absolute_byte_offset: 0,
|
absolute_byte_offset: 0,
|
||||||
@ -188,7 +190,7 @@ impl<'a> Sunk<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_sink_match(
|
pub(crate) fn from_sink_match(
|
||||||
sunk: &'a SinkMatch<'a>,
|
sunk: &'a SinkMatch<'a>,
|
||||||
original_matches: &'a [Match],
|
original_matches: &'a [Match],
|
||||||
replacement: Option<(&'a [u8], &'a [Match])>,
|
replacement: Option<(&'a [u8], &'a [Match])>,
|
||||||
@ -196,17 +198,17 @@ impl<'a> Sunk<'a> {
|
|||||||
let (bytes, matches) =
|
let (bytes, matches) =
|
||||||
replacement.unwrap_or_else(|| (sunk.bytes(), original_matches));
|
replacement.unwrap_or_else(|| (sunk.bytes(), original_matches));
|
||||||
Sunk {
|
Sunk {
|
||||||
bytes: bytes,
|
bytes,
|
||||||
absolute_byte_offset: sunk.absolute_byte_offset(),
|
absolute_byte_offset: sunk.absolute_byte_offset(),
|
||||||
line_number: sunk.line_number(),
|
line_number: sunk.line_number(),
|
||||||
context_kind: None,
|
context_kind: None,
|
||||||
matches: matches,
|
matches,
|
||||||
original_matches: original_matches,
|
original_matches,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_sink_context(
|
pub(crate) fn from_sink_context(
|
||||||
sunk: &'a SinkContext<'a>,
|
sunk: &'a SinkContext<'a>,
|
||||||
original_matches: &'a [Match],
|
original_matches: &'a [Match],
|
||||||
replacement: Option<(&'a [u8], &'a [Match])>,
|
replacement: Option<(&'a [u8], &'a [Match])>,
|
||||||
@ -214,47 +216,47 @@ impl<'a> Sunk<'a> {
|
|||||||
let (bytes, matches) =
|
let (bytes, matches) =
|
||||||
replacement.unwrap_or_else(|| (sunk.bytes(), original_matches));
|
replacement.unwrap_or_else(|| (sunk.bytes(), original_matches));
|
||||||
Sunk {
|
Sunk {
|
||||||
bytes: bytes,
|
bytes,
|
||||||
absolute_byte_offset: sunk.absolute_byte_offset(),
|
absolute_byte_offset: sunk.absolute_byte_offset(),
|
||||||
line_number: sunk.line_number(),
|
line_number: sunk.line_number(),
|
||||||
context_kind: Some(sunk.kind()),
|
context_kind: Some(sunk.kind()),
|
||||||
matches: matches,
|
matches,
|
||||||
original_matches: original_matches,
|
original_matches,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn context_kind(&self) -> Option<&'a SinkContextKind> {
|
pub(crate) fn context_kind(&self) -> Option<&'a SinkContextKind> {
|
||||||
self.context_kind
|
self.context_kind
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn bytes(&self) -> &'a [u8] {
|
pub(crate) fn bytes(&self) -> &'a [u8] {
|
||||||
self.bytes
|
self.bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn matches(&self) -> &'a [Match] {
|
pub(crate) fn matches(&self) -> &'a [Match] {
|
||||||
self.matches
|
self.matches
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn original_matches(&self) -> &'a [Match] {
|
pub(crate) fn original_matches(&self) -> &'a [Match] {
|
||||||
self.original_matches
|
self.original_matches
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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())
|
LineIter::new(line_term, self.bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn absolute_byte_offset(&self) -> u64 {
|
pub(crate) fn absolute_byte_offset(&self) -> u64 {
|
||||||
self.absolute_byte_offset
|
self.absolute_byte_offset
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn line_number(&self) -> Option<u64> {
|
pub(crate) fn line_number(&self) -> Option<u64> {
|
||||||
self.line_number
|
self.line_number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,7 +283,7 @@ impl<'a> Sunk<'a> {
|
|||||||
pub struct PrinterPath<'a> {
|
pub struct PrinterPath<'a> {
|
||||||
path: &'a Path,
|
path: &'a Path,
|
||||||
bytes: Cow<'a, [u8]>,
|
bytes: Cow<'a, [u8]>,
|
||||||
hyperlink_path: OnceCell<Option<HyperlinkPath>>,
|
hyperlink_path: std::cell::OnceCell<Option<HyperlinkPath>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PrinterPath<'a> {
|
impl<'a> PrinterPath<'a> {
|
||||||
@ -290,7 +292,7 @@ impl<'a> PrinterPath<'a> {
|
|||||||
PrinterPath {
|
PrinterPath {
|
||||||
path,
|
path,
|
||||||
bytes: Vec::from_path_lossy(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
|
&self.bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a hyperlink for this path and the given line and column, using the specified
|
/// Creates a hyperlink for this path and the given line and column, using
|
||||||
/// pattern. Uses the given buffer to store the hyperlink.
|
/// the specified pattern. Uses the given buffer to store the hyperlink.
|
||||||
pub fn create_hyperlink_spec<'b>(
|
pub fn create_hyperlink_spec<'b>(
|
||||||
&self,
|
&self,
|
||||||
pattern: &HyperlinkPattern,
|
pattern: &HyperlinkPattern,
|
||||||
@ -365,7 +367,7 @@ impl<'a> PrinterPath<'a> {
|
|||||||
/// with the Deserialize impl for std::time::Duration, since this type only
|
/// with the Deserialize impl for std::time::Duration, since this type only
|
||||||
/// adds new fields.
|
/// adds new fields.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
#[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 {
|
impl fmt::Display for NiceDuration {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
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 {
|
impl Serialize for NiceDuration {
|
||||||
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||||
use serde::ser::SerializeStruct;
|
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
|
/// This stops trimming a prefix as soon as it sees non-whitespace or a line
|
||||||
/// terminator.
|
/// terminator.
|
||||||
pub fn trim_ascii_prefix(
|
pub(crate) fn trim_ascii_prefix(
|
||||||
line_term: LineTerminator,
|
line_term: LineTerminator,
|
||||||
slice: &[u8],
|
slice: &[u8],
|
||||||
range: Match,
|
range: Match,
|
||||||
@ -422,7 +424,7 @@ pub fn trim_ascii_prefix(
|
|||||||
range.with_start(range.start() + count)
|
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,
|
searcher: &Searcher,
|
||||||
matcher: M,
|
matcher: M,
|
||||||
mut bytes: &[u8],
|
mut bytes: &[u8],
|
||||||
@ -482,7 +484,7 @@ where
|
|||||||
/// Given a buf and some bounds, if there is a line terminator at the end of
|
/// 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
|
/// the given bounds in buf, then the bounds are trimmed to remove the line
|
||||||
/// terminator.
|
/// terminator.
|
||||||
pub fn trim_line_terminator(
|
pub(crate) fn trim_line_terminator(
|
||||||
searcher: &Searcher,
|
searcher: &Searcher,
|
||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
line: &mut Match,
|
line: &mut Match,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user