summary.rs (ripgrep-12.1.1) | : | summary.rs (ripgrep-13.0.0) | ||
---|---|---|---|---|
use std::cell::RefCell; | use std::cell::RefCell; | |||
use std::io::{self, Write}; | use std::io::{self, Write}; | |||
use std::path::Path; | use std::path::Path; | |||
use std::sync::Arc; | use std::sync::Arc; | |||
use std::time::Instant; | use std::time::Instant; | |||
use grep_matcher::Matcher; | use grep_matcher::Matcher; | |||
use grep_searcher::{Searcher, Sink, SinkError, SinkFinish, SinkMatch}; | use grep_searcher::{Searcher, Sink, SinkError, SinkFinish, SinkMatch}; | |||
use termcolor::{ColorSpec, NoColor, WriteColor}; | use termcolor::{ColorSpec, NoColor, WriteColor}; | |||
use color::ColorSpecs; | use crate::color::ColorSpecs; | |||
use counter::CounterWriter; | use crate::counter::CounterWriter; | |||
use stats::Stats; | use crate::stats::Stats; | |||
use util::PrinterPath; | use crate::util::{find_iter_at_in_context, PrinterPath}; | |||
/// The configuration for the summary printer. | /// The configuration for the summary printer. | |||
/// | /// | |||
/// This is manipulated by the SummaryBuilder and then referenced by the actual | /// This is manipulated by the SummaryBuilder and then referenced by the actual | |||
/// implementation. Once a printer is build, the configuration is frozen and | /// implementation. Once a printer is build, the configuration is frozen and | |||
/// cannot changed. | /// cannot changed. | |||
#[derive(Debug, Clone)] | #[derive(Debug, Clone)] | |||
struct Config { | struct Config { | |||
kind: SummaryKind, | kind: SummaryKind, | |||
colors: ColorSpecs, | colors: ColorSpecs, | |||
skipping to change at line 460 | skipping to change at line 460 | |||
/// * `'p` refers to the lifetime of the file path, if one is provided. When | /// * `'p` refers to the lifetime of the file path, if one is provided. When | |||
/// no file path is given, then this is `'static`. | /// no file path is given, then this is `'static`. | |||
/// * `'s` refers to the lifetime of the | /// * `'s` refers to the lifetime of the | |||
/// [`Summary`](struct.Summary.html) | /// [`Summary`](struct.Summary.html) | |||
/// printer that this type borrows. | /// printer that this type borrows. | |||
/// * `M` refers to the type of matcher used by | /// * `M` refers to the type of matcher used by | |||
/// `grep_searcher::Searcher` that is reporting results to this sink. | /// `grep_searcher::Searcher` that is reporting results to this sink. | |||
/// * `W` refers to the underlying writer that this printer is writing its | /// * `W` refers to the underlying writer that this printer is writing its | |||
/// output to. | /// output to. | |||
#[derive(Debug)] | #[derive(Debug)] | |||
pub struct SummarySink<'p, 's, M: Matcher, W: 's> { | pub struct SummarySink<'p, 's, M: Matcher, W> { | |||
matcher: M, | matcher: M, | |||
summary: &'s mut Summary<W>, | summary: &'s mut Summary<W>, | |||
path: Option<PrinterPath<'p>>, | path: Option<PrinterPath<'p>>, | |||
start_time: Instant, | start_time: Instant, | |||
match_count: u64, | match_count: u64, | |||
binary_byte_offset: Option<u64>, | binary_byte_offset: Option<u64>, | |||
stats: Option<Stats>, | stats: Option<Stats>, | |||
} | } | |||
impl<'p, 's, M: Matcher, W: WriteColor> SummarySink<'p, 's, M, W> { | impl<'p, 's, M: Matcher, W: WriteColor> SummarySink<'p, 's, M, W> { | |||
skipping to change at line 507 | skipping to change at line 507 | |||
/// Return a reference to the stats produced by the printer for all | /// Return a reference to the stats produced by the printer for all | |||
/// searches executed on this sink. | /// searches executed on this sink. | |||
/// | /// | |||
/// This only returns stats if they were requested via the | /// This only returns stats if they were requested via the | |||
/// [`SummaryBuilder`](struct.SummaryBuilder.html) | /// [`SummaryBuilder`](struct.SummaryBuilder.html) | |||
/// configuration. | /// configuration. | |||
pub fn stats(&self) -> Option<&Stats> { | pub fn stats(&self) -> Option<&Stats> { | |||
self.stats.as_ref() | self.stats.as_ref() | |||
} | } | |||
/// Returns true if and only if the searcher may report matches over | ||||
/// multiple lines. | ||||
/// | ||||
/// Note that this doesn't just return whether the searcher is in multi | ||||
/// line mode, but also checks if the mater can match over multiple lines. | ||||
/// If it can't, then we don't need multi line handling, even if the | ||||
/// searcher has multi line mode enabled. | ||||
fn multi_line(&self, searcher: &Searcher) -> bool { | ||||
searcher.multi_line_with_matcher(&self.matcher) | ||||
} | ||||
/// Returns true if this printer should quit. | /// Returns true if this printer should quit. | |||
/// | /// | |||
/// This implements the logic for handling quitting after seeing a certain | /// This implements the logic for handling quitting after seeing a certain | |||
/// amount of matches. In most cases, the logic is simple, but we must | /// amount of matches. In most cases, the logic is simple, but we must | |||
/// permit all "after" contextual lines to print after reaching the limit. | /// permit all "after" contextual lines to print after reaching the limit. | |||
fn should_quit(&self) -> bool { | fn should_quit(&self) -> bool { | |||
let limit = match self.summary.config.max_matches { | let limit = match self.summary.config.max_matches { | |||
None => return false, | None => return false, | |||
Some(limit) => limit, | Some(limit) => limit, | |||
}; | }; | |||
skipping to change at line 582 | skipping to change at line 593 | |||
fn write(&self, buf: &[u8]) -> io::Result<()> { | fn write(&self, buf: &[u8]) -> io::Result<()> { | |||
self.summary.wtr.borrow_mut().write_all(buf) | self.summary.wtr.borrow_mut().write_all(buf) | |||
} | } | |||
} | } | |||
impl<'p, 's, M: Matcher, W: WriteColor> Sink for SummarySink<'p, 's, M, W> { | impl<'p, 's, M: Matcher, W: WriteColor> Sink for SummarySink<'p, 's, M, W> { | |||
type Error = io::Error; | type Error = io::Error; | |||
fn matched( | fn matched( | |||
&mut self, | &mut self, | |||
_searcher: &Searcher, | searcher: &Searcher, | |||
mat: &SinkMatch, | mat: &SinkMatch<'_>, | |||
) -> Result<bool, io::Error> { | ) -> Result<bool, io::Error> { | |||
self.match_count += 1; | let is_multi_line = self.multi_line(searcher); | |||
if let Some(ref mut stats) = self.stats { | let sink_match_count = if self.stats.is_none() && !is_multi_line { | |||
let mut match_count = 0; | 1 | |||
self.matcher | } else { | |||
.find_iter(mat.bytes(), |_| { | // This gives us as many bytes as the searcher can offer. This | |||
match_count += 1; | // isn't guaranteed to hold the necessary context to get match | |||
// detection correct (because of look-around), but it does in | ||||
// practice. | ||||
let buf = mat.buffer(); | ||||
let range = mat.bytes_range_in_buffer(); | ||||
let mut count = 0; | ||||
find_iter_at_in_context( | ||||
searcher, | ||||
&self.matcher, | ||||
buf, | ||||
range, | ||||
|_| { | ||||
count += 1; | ||||
true | true | |||
}) | }, | |||
.map_err(io::Error::error_message)?; | )?; | |||
if match_count == 0 { | count | |||
// It is possible for the match count to be zero when | }; | |||
// look-around is used. Since `SinkMatch` won't necessarily | if is_multi_line { | |||
// contain the look-around in its match span, the search here | self.match_count += sink_match_count; | |||
// could fail to find anything. | } else { | |||
// | self.match_count += 1; | |||
// It seems likely that setting match_count=1 here is probably | } | |||
// wrong in some cases, but I don't think we can do any | if let Some(ref mut stats) = self.stats { | |||
// better. (Because this printer cannot assume that subsequent | stats.add_matches(sink_match_count); | |||
// contents have been loaded into memory, so we have no way of | ||||
// increasing the search span here.) | ||||
match_count = 1; | ||||
} | ||||
stats.add_matches(match_count); | ||||
stats.add_matched_lines(mat.lines().count() as u64); | stats.add_matched_lines(mat.lines().count() as u64); | |||
} else if self.summary.config.kind.quit_early() { | } else if self.summary.config.kind.quit_early() { | |||
return Ok(false); | return Ok(false); | |||
} | } | |||
Ok(!self.should_quit()) | Ok(!self.should_quit()) | |||
} | } | |||
fn begin(&mut self, _searcher: &Searcher) -> Result<bool, io::Error> { | fn begin(&mut self, _searcher: &Searcher) -> Result<bool, io::Error> { | |||
if self.path.is_none() && self.summary.config.kind.requires_path() { | if self.path.is_none() && self.summary.config.kind.requires_path() { | |||
return Err(io::Error::error_message(format!( | return Err(io::Error::error_message(format!( | |||
End of changes. 6 change blocks. | ||||
29 lines changed or deleted | 47 lines changed or added |