|
|
|
@ -46,7 +46,6 @@ use crate::{
|
|
|
|
|
messages::{set_ignore_messages, set_messages},
|
|
|
|
|
search::{PatternMatcher, Printer, SearchWorker, SearchWorkerBuilder},
|
|
|
|
|
subject::{Subject, SubjectBuilder},
|
|
|
|
|
Result,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// The command that ripgrep should execute based on the command line
|
|
|
|
@ -129,7 +128,7 @@ impl Args {
|
|
|
|
|
/// ripgrep, then print the version and exit.
|
|
|
|
|
///
|
|
|
|
|
/// Also, initialize a global logger.
|
|
|
|
|
pub fn parse() -> Result<Args> {
|
|
|
|
|
pub fn parse() -> anyhow::Result<Args> {
|
|
|
|
|
// We parse the args given on CLI. This does not include args from
|
|
|
|
|
// the config. We use the CLI args as an initial configuration while
|
|
|
|
|
// trying to parse config files. If a config file exists and has
|
|
|
|
@ -140,7 +139,7 @@ impl Args {
|
|
|
|
|
set_ignore_messages(!early_matches.is_present("no-ignore-messages"));
|
|
|
|
|
|
|
|
|
|
if let Err(err) = Logger::init() {
|
|
|
|
|
return Err(format!("failed to initialize logger: {}", err).into());
|
|
|
|
|
anyhow::bail!("failed to initialize logger: {err}");
|
|
|
|
|
}
|
|
|
|
|
if early_matches.is_present("trace") {
|
|
|
|
|
log::set_max_level(log::LevelFilter::Trace);
|
|
|
|
@ -194,7 +193,7 @@ impl Args {
|
|
|
|
|
/// search results.
|
|
|
|
|
///
|
|
|
|
|
/// The returned printer will write results to the given writer.
|
|
|
|
|
fn printer<W: WriteColor>(&self, wtr: W) -> Result<Printer<W>> {
|
|
|
|
|
fn printer<W: WriteColor>(&self, wtr: W) -> anyhow::Result<Printer<W>> {
|
|
|
|
|
match self.matches().output_kind() {
|
|
|
|
|
OutputKind::Standard => {
|
|
|
|
|
let separator_search = self.command() == Command::Search;
|
|
|
|
@ -218,7 +217,7 @@ impl Args {
|
|
|
|
|
impl Args {
|
|
|
|
|
/// Create a new buffer writer for multi-threaded printing with color
|
|
|
|
|
/// support.
|
|
|
|
|
pub fn buffer_writer(&self) -> Result<BufferWriter> {
|
|
|
|
|
pub fn buffer_writer(&self) -> anyhow::Result<BufferWriter> {
|
|
|
|
|
let mut wtr = BufferWriter::stdout(self.matches().color_choice());
|
|
|
|
|
wtr.separator(self.matches().file_separator()?);
|
|
|
|
|
Ok(wtr)
|
|
|
|
@ -236,7 +235,7 @@ impl Args {
|
|
|
|
|
pub fn path_printer<W: WriteColor>(
|
|
|
|
|
&self,
|
|
|
|
|
wtr: W,
|
|
|
|
|
) -> Result<PathPrinter<W>> {
|
|
|
|
|
) -> anyhow::Result<PathPrinter<W>> {
|
|
|
|
|
let mut builder = PathPrinterBuilder::new();
|
|
|
|
|
builder
|
|
|
|
|
.color_specs(self.matches().color_specs()?)
|
|
|
|
@ -253,7 +252,7 @@ impl Args {
|
|
|
|
|
|
|
|
|
|
/// Returns true if and only if the search should quit after finding the
|
|
|
|
|
/// first match.
|
|
|
|
|
pub fn quit_after_match(&self) -> Result<bool> {
|
|
|
|
|
pub fn quit_after_match(&self) -> anyhow::Result<bool> {
|
|
|
|
|
Ok(self.matches().is_present("quiet") && self.stats()?.is_none())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -263,7 +262,7 @@ impl Args {
|
|
|
|
|
pub fn search_worker<W: WriteColor>(
|
|
|
|
|
&self,
|
|
|
|
|
wtr: W,
|
|
|
|
|
) -> Result<SearchWorker<W>> {
|
|
|
|
|
) -> anyhow::Result<SearchWorker<W>> {
|
|
|
|
|
let matches = self.matches();
|
|
|
|
|
let matcher = self.matcher().clone();
|
|
|
|
|
let printer = self.printer(wtr)?;
|
|
|
|
@ -284,7 +283,7 @@ impl Args {
|
|
|
|
|
///
|
|
|
|
|
/// When this returns a `Stats` value, then it is guaranteed that the
|
|
|
|
|
/// search worker will be configured to track statistics as well.
|
|
|
|
|
pub fn stats(&self) -> Result<Option<Stats>> {
|
|
|
|
|
pub fn stats(&self) -> anyhow::Result<Option<Stats>> {
|
|
|
|
|
Ok(if self.command().is_search() && self.matches().stats() {
|
|
|
|
|
Some(Stats::new())
|
|
|
|
|
} else {
|
|
|
|
@ -318,12 +317,12 @@ impl Args {
|
|
|
|
|
///
|
|
|
|
|
/// If there was a problem reading and parsing the type definitions, then
|
|
|
|
|
/// this returns an error.
|
|
|
|
|
pub fn type_defs(&self) -> Result<Vec<FileTypeDef>> {
|
|
|
|
|
pub fn type_defs(&self) -> anyhow::Result<Vec<FileTypeDef>> {
|
|
|
|
|
Ok(self.matches().types()?.definitions().to_vec())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Return a walker that never uses additional threads.
|
|
|
|
|
pub fn walker(&self) -> Result<Walk> {
|
|
|
|
|
pub fn walker(&self) -> anyhow::Result<Walk> {
|
|
|
|
|
Ok(self
|
|
|
|
|
.matches()
|
|
|
|
|
.walker_builder(self.paths(), self.0.threads)?
|
|
|
|
@ -371,7 +370,7 @@ impl Args {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Return a parallel walker that may use additional threads.
|
|
|
|
|
pub fn walker_parallel(&self) -> Result<WalkParallel> {
|
|
|
|
|
pub fn walker_parallel(&self) -> anyhow::Result<WalkParallel> {
|
|
|
|
|
Ok(self
|
|
|
|
|
.matches()
|
|
|
|
|
.walker_builder(self.paths(), self.0.threads)?
|
|
|
|
@ -434,7 +433,7 @@ impl SortBy {
|
|
|
|
|
|
|
|
|
|
/// Try to check that the sorting criteria selected is actually supported.
|
|
|
|
|
/// If it isn't, then an error is returned.
|
|
|
|
|
fn check(&self) -> Result<()> {
|
|
|
|
|
fn check(&self) -> anyhow::Result<()> {
|
|
|
|
|
match self.kind {
|
|
|
|
|
SortByKind::None | SortByKind::Path => {}
|
|
|
|
|
SortByKind::LastModified => {
|
|
|
|
@ -509,7 +508,7 @@ impl ArgMatches {
|
|
|
|
|
///
|
|
|
|
|
/// If there are no additional arguments from the environment (e.g., a
|
|
|
|
|
/// config file), then the given matches are returned as is.
|
|
|
|
|
fn reconfigure(self) -> Result<ArgMatches> {
|
|
|
|
|
fn reconfigure(self) -> anyhow::Result<ArgMatches> {
|
|
|
|
|
// If the end user says no config, then respect it.
|
|
|
|
|
if self.is_present("no-config") {
|
|
|
|
|
log::debug!(
|
|
|
|
@ -534,7 +533,7 @@ impl ArgMatches {
|
|
|
|
|
|
|
|
|
|
/// Convert the result of parsing CLI arguments into ripgrep's higher level
|
|
|
|
|
/// configuration structure.
|
|
|
|
|
fn to_args(self) -> Result<Args> {
|
|
|
|
|
fn to_args(self) -> anyhow::Result<Args> {
|
|
|
|
|
// We compute these once since they could be large.
|
|
|
|
|
let patterns = self.patterns()?;
|
|
|
|
|
let matcher = self.matcher(&patterns)?;
|
|
|
|
@ -591,7 +590,7 @@ impl ArgMatches {
|
|
|
|
|
///
|
|
|
|
|
/// If there was a problem building the matcher (e.g., a syntax error),
|
|
|
|
|
/// then this returns an error.
|
|
|
|
|
fn matcher(&self, patterns: &[String]) -> Result<PatternMatcher> {
|
|
|
|
|
fn matcher(&self, patterns: &[String]) -> anyhow::Result<PatternMatcher> {
|
|
|
|
|
if self.is_present("pcre2") {
|
|
|
|
|
self.matcher_engine("pcre2", patterns)
|
|
|
|
|
} else if self.is_present("auto-hybrid-regex") {
|
|
|
|
@ -611,13 +610,13 @@ impl ArgMatches {
|
|
|
|
|
&self,
|
|
|
|
|
engine: &str,
|
|
|
|
|
patterns: &[String],
|
|
|
|
|
) -> Result<PatternMatcher> {
|
|
|
|
|
) -> anyhow::Result<PatternMatcher> {
|
|
|
|
|
match engine {
|
|
|
|
|
"default" => {
|
|
|
|
|
let matcher = match self.matcher_rust(patterns) {
|
|
|
|
|
Ok(matcher) => matcher,
|
|
|
|
|
Err(err) => {
|
|
|
|
|
return Err(From::from(suggest(err.to_string())));
|
|
|
|
|
anyhow::bail!(suggest(err.to_string()));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
Ok(PatternMatcher::RustRegex(matcher))
|
|
|
|
@ -628,9 +627,9 @@ impl ArgMatches {
|
|
|
|
|
Ok(PatternMatcher::PCRE2(matcher))
|
|
|
|
|
}
|
|
|
|
|
#[cfg(not(feature = "pcre2"))]
|
|
|
|
|
"pcre2" => Err(From::from(
|
|
|
|
|
"pcre2" => anyhow::bail!(
|
|
|
|
|
"PCRE2 is not available in this build of ripgrep",
|
|
|
|
|
)),
|
|
|
|
|
),
|
|
|
|
|
"auto" => {
|
|
|
|
|
let rust_err = match self.matcher_rust(patterns) {
|
|
|
|
|
Ok(matcher) => {
|
|
|
|
@ -647,21 +646,18 @@ impl ArgMatches {
|
|
|
|
|
Ok(matcher) => return Ok(matcher),
|
|
|
|
|
Err(err) => err,
|
|
|
|
|
};
|
|
|
|
|
Err(From::from(format!(
|
|
|
|
|
let divider = "~".repeat(79);
|
|
|
|
|
anyhow::bail!(
|
|
|
|
|
"regex could not be compiled with either the default \
|
|
|
|
|
regex engine or with PCRE2.\n\n\
|
|
|
|
|
default regex engine error:\n{}\n{}\n{}\n\n\
|
|
|
|
|
PCRE2 regex engine error:\n{}",
|
|
|
|
|
"~".repeat(79),
|
|
|
|
|
rust_err,
|
|
|
|
|
"~".repeat(79),
|
|
|
|
|
pcre_err,
|
|
|
|
|
)))
|
|
|
|
|
default regex engine error:\n\
|
|
|
|
|
{divider}\n\
|
|
|
|
|
{rust_err}\n\
|
|
|
|
|
{divider}\n\n\
|
|
|
|
|
PCRE2 regex engine error:\n{pcre_err}",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
_ => Err(From::from(format!(
|
|
|
|
|
"unrecognized regex engine '{}'",
|
|
|
|
|
engine
|
|
|
|
|
))),
|
|
|
|
|
_ => anyhow::bail!("unrecognized regex engine '{engine}'"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -669,7 +665,10 @@ impl ArgMatches {
|
|
|
|
|
///
|
|
|
|
|
/// If there was a problem building the matcher (such as a regex syntax
|
|
|
|
|
/// error), then an error is returned.
|
|
|
|
|
fn matcher_rust(&self, patterns: &[String]) -> Result<RustRegexMatcher> {
|
|
|
|
|
fn matcher_rust(
|
|
|
|
|
&self,
|
|
|
|
|
patterns: &[String],
|
|
|
|
|
) -> anyhow::Result<RustRegexMatcher> {
|
|
|
|
|
let mut builder = RustRegexMatcherBuilder::new();
|
|
|
|
|
builder
|
|
|
|
|
.case_smart(self.case_smart())
|
|
|
|
@ -707,7 +706,7 @@ impl ArgMatches {
|
|
|
|
|
}
|
|
|
|
|
match builder.build_many(patterns) {
|
|
|
|
|
Ok(m) => Ok(m),
|
|
|
|
|
Err(err) => Err(From::from(suggest_multiline(err.to_string()))),
|
|
|
|
|
Err(err) => anyhow::bail!(suggest_multiline(err.to_string())),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -716,7 +715,10 @@ impl ArgMatches {
|
|
|
|
|
/// If there was a problem building the matcher (such as a regex syntax
|
|
|
|
|
/// error), then an error is returned.
|
|
|
|
|
#[cfg(feature = "pcre2")]
|
|
|
|
|
fn matcher_pcre2(&self, patterns: &[String]) -> Result<PCRE2RegexMatcher> {
|
|
|
|
|
fn matcher_pcre2(
|
|
|
|
|
&self,
|
|
|
|
|
patterns: &[String],
|
|
|
|
|
) -> anyhow::Result<PCRE2RegexMatcher> {
|
|
|
|
|
let mut builder = PCRE2RegexMatcherBuilder::new();
|
|
|
|
|
builder
|
|
|
|
|
.case_smart(self.case_smart())
|
|
|
|
@ -748,7 +750,7 @@ impl ArgMatches {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Build a JSON printer that writes results to the given writer.
|
|
|
|
|
fn printer_json<W: io::Write>(&self, wtr: W) -> Result<JSON<W>> {
|
|
|
|
|
fn printer_json<W: io::Write>(&self, wtr: W) -> anyhow::Result<JSON<W>> {
|
|
|
|
|
let mut builder = JSONBuilder::new();
|
|
|
|
|
builder
|
|
|
|
|
.pretty(false)
|
|
|
|
@ -774,7 +776,7 @@ impl ArgMatches {
|
|
|
|
|
paths: &[PathBuf],
|
|
|
|
|
wtr: W,
|
|
|
|
|
separator_search: bool,
|
|
|
|
|
) -> Result<Standard<W>> {
|
|
|
|
|
) -> anyhow::Result<Standard<W>> {
|
|
|
|
|
let mut builder = StandardBuilder::new();
|
|
|
|
|
builder
|
|
|
|
|
.color_specs(self.color_specs()?)
|
|
|
|
@ -813,7 +815,7 @@ impl ArgMatches {
|
|
|
|
|
&self,
|
|
|
|
|
paths: &[PathBuf],
|
|
|
|
|
wtr: W,
|
|
|
|
|
) -> Result<Summary<W>> {
|
|
|
|
|
) -> anyhow::Result<Summary<W>> {
|
|
|
|
|
let mut builder = SummaryBuilder::new();
|
|
|
|
|
builder
|
|
|
|
|
.kind(self.summary_kind().expect("summary format"))
|
|
|
|
@ -830,7 +832,7 @@ impl ArgMatches {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Build a searcher from the command line parameters.
|
|
|
|
|
fn searcher(&self, paths: &[PathBuf]) -> Result<Searcher> {
|
|
|
|
|
fn searcher(&self, paths: &[PathBuf]) -> anyhow::Result<Searcher> {
|
|
|
|
|
let (ctx_before, ctx_after) = self.contexts()?;
|
|
|
|
|
let line_term = if self.is_present("crlf") {
|
|
|
|
|
LineTerminator::crlf()
|
|
|
|
@ -871,7 +873,7 @@ impl ArgMatches {
|
|
|
|
|
&self,
|
|
|
|
|
paths: &[PathBuf],
|
|
|
|
|
threads: usize,
|
|
|
|
|
) -> Result<WalkBuilder> {
|
|
|
|
|
) -> anyhow::Result<WalkBuilder> {
|
|
|
|
|
let mut builder = WalkBuilder::new(&paths[0]);
|
|
|
|
|
for path in &paths[1..] {
|
|
|
|
|
builder.add(path);
|
|
|
|
@ -994,7 +996,7 @@ impl ArgMatches {
|
|
|
|
|
///
|
|
|
|
|
/// If the was a problem parsing any of the provided specs, then an error
|
|
|
|
|
/// is returned.
|
|
|
|
|
fn color_specs(&self) -> Result<ColorSpecs> {
|
|
|
|
|
fn color_specs(&self) -> anyhow::Result<ColorSpecs> {
|
|
|
|
|
// Start with a default set of color specs.
|
|
|
|
|
let mut specs = default_color_specs();
|
|
|
|
|
for spec_str in self.values_of_lossy_vec("colors") {
|
|
|
|
@ -1017,7 +1019,7 @@ impl ArgMatches {
|
|
|
|
|
///
|
|
|
|
|
/// If there was a problem parsing the values from the user as an integer,
|
|
|
|
|
/// then an error is returned.
|
|
|
|
|
fn contexts(&self) -> Result<(usize, usize)> {
|
|
|
|
|
fn contexts(&self) -> anyhow::Result<(usize, usize)> {
|
|
|
|
|
let both = self.usize_of("context")?.unwrap_or(0);
|
|
|
|
|
let after = self.usize_of("after-context")?.unwrap_or(both);
|
|
|
|
|
let before = self.usize_of("before-context")?.unwrap_or(both);
|
|
|
|
@ -1061,7 +1063,7 @@ impl ArgMatches {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Parse the dfa-size-limit argument option into a byte count.
|
|
|
|
|
fn dfa_size_limit(&self) -> Result<Option<usize>> {
|
|
|
|
|
fn dfa_size_limit(&self) -> anyhow::Result<Option<usize>> {
|
|
|
|
|
let r = self.parse_human_readable_size("dfa-size-limit")?;
|
|
|
|
|
u64_to_usize("dfa-size-limit", r)
|
|
|
|
|
}
|
|
|
|
@ -1072,7 +1074,7 @@ impl ArgMatches {
|
|
|
|
|
/// if set to automatic, the Searcher will do BOM sniffing for UTF-16
|
|
|
|
|
/// and transcode seamlessly. If disabled, no BOM sniffing nor transcoding
|
|
|
|
|
/// will occur.
|
|
|
|
|
fn encoding(&self) -> Result<EncodingMode> {
|
|
|
|
|
fn encoding(&self) -> anyhow::Result<EncodingMode> {
|
|
|
|
|
if self.is_present("no-encoding") {
|
|
|
|
|
return Ok(EncodingMode::Auto);
|
|
|
|
|
}
|
|
|
|
@ -1092,7 +1094,7 @@ impl ArgMatches {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Return the file separator to use based on the CLI configuration.
|
|
|
|
|
fn file_separator(&self) -> Result<Option<Vec<u8>>> {
|
|
|
|
|
fn file_separator(&self) -> anyhow::Result<Option<Vec<u8>>> {
|
|
|
|
|
// File separators are only used for the standard grep-line format.
|
|
|
|
|
if self.output_kind() != OutputKind::Standard {
|
|
|
|
|
return Ok(None);
|
|
|
|
@ -1130,7 +1132,7 @@ impl ArgMatches {
|
|
|
|
|
/// for the current system is used if the value is not set.
|
|
|
|
|
///
|
|
|
|
|
/// If an invalid pattern is provided, then an error is returned.
|
|
|
|
|
fn hyperlink_config(&self) -> Result<HyperlinkConfig> {
|
|
|
|
|
fn hyperlink_config(&self) -> anyhow::Result<HyperlinkConfig> {
|
|
|
|
|
let mut env = HyperlinkEnvironment::new();
|
|
|
|
|
env.host(hostname(self.value_of_os("hostname-bin")))
|
|
|
|
|
.wsl_prefix(wsl_prefix());
|
|
|
|
@ -1140,8 +1142,7 @@ impl ArgMatches {
|
|
|
|
|
Some(format) => match format.parse() {
|
|
|
|
|
Ok(format) => format,
|
|
|
|
|
Err(err) => {
|
|
|
|
|
let msg = format!("invalid hyperlink format: {err}");
|
|
|
|
|
return Err(msg.into());
|
|
|
|
|
anyhow::bail!("invalid hyperlink format: {err}");
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
@ -1204,7 +1205,7 @@ impl ArgMatches {
|
|
|
|
|
/// The maximum number of columns allowed on each line.
|
|
|
|
|
///
|
|
|
|
|
/// If `0` is provided, then this returns `None`.
|
|
|
|
|
fn max_columns(&self) -> Result<Option<u64>> {
|
|
|
|
|
fn max_columns(&self) -> anyhow::Result<Option<u64>> {
|
|
|
|
|
Ok(self.usize_of_nonzero("max-columns")?.map(|n| n as u64))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1215,12 +1216,12 @@ impl ArgMatches {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The maximum number of matches permitted.
|
|
|
|
|
fn max_count(&self) -> Result<Option<u64>> {
|
|
|
|
|
fn max_count(&self) -> anyhow::Result<Option<u64>> {
|
|
|
|
|
Ok(self.usize_of("max-count")?.map(|n| n as u64))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Parses the max-filesize argument option into a byte count.
|
|
|
|
|
fn max_file_size(&self) -> Result<Option<u64>> {
|
|
|
|
|
fn max_file_size(&self) -> anyhow::Result<Option<u64>> {
|
|
|
|
|
self.parse_human_readable_size("max-filesize")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1311,7 +1312,7 @@ impl ArgMatches {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Builds the set of glob overrides from the command line flags.
|
|
|
|
|
fn overrides(&self) -> Result<Override> {
|
|
|
|
|
fn overrides(&self) -> anyhow::Result<Override> {
|
|
|
|
|
let globs = self.values_of_lossy_vec("glob");
|
|
|
|
|
let iglobs = self.values_of_lossy_vec("iglob");
|
|
|
|
|
if globs.is_empty() && iglobs.is_empty() {
|
|
|
|
@ -1378,7 +1379,7 @@ impl ArgMatches {
|
|
|
|
|
///
|
|
|
|
|
/// If the provided path separator is more than a single byte, then an
|
|
|
|
|
/// error is returned.
|
|
|
|
|
fn path_separator(&self) -> Result<Option<u8>> {
|
|
|
|
|
fn path_separator(&self) -> anyhow::Result<Option<u8>> {
|
|
|
|
|
let sep = match self.value_of_os("path-separator") {
|
|
|
|
|
None => return Ok(None),
|
|
|
|
|
Some(sep) => cli::unescape_os(&sep),
|
|
|
|
@ -1386,14 +1387,14 @@ impl ArgMatches {
|
|
|
|
|
if sep.is_empty() {
|
|
|
|
|
Ok(None)
|
|
|
|
|
} else if sep.len() > 1 {
|
|
|
|
|
Err(From::from(format!(
|
|
|
|
|
anyhow::bail!(
|
|
|
|
|
"A path separator must be exactly one byte, but \
|
|
|
|
|
the given separator is {} bytes: {}\n\
|
|
|
|
|
In some shells on Windows '/' is automatically \
|
|
|
|
|
expanded. Use '//' instead.",
|
|
|
|
|
sep.len(),
|
|
|
|
|
cli::escape(&sep),
|
|
|
|
|
)))
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
Ok(Some(sep[0]))
|
|
|
|
|
}
|
|
|
|
@ -1433,7 +1434,7 @@ impl ArgMatches {
|
|
|
|
|
/// This includes reading the -e/--regexp and -f/--file flags.
|
|
|
|
|
///
|
|
|
|
|
/// If any pattern is invalid UTF-8, then an error is returned.
|
|
|
|
|
fn patterns(&self) -> Result<Vec<String>> {
|
|
|
|
|
fn patterns(&self) -> anyhow::Result<Vec<String>> {
|
|
|
|
|
if self.is_present("files") || self.is_present("type-list") {
|
|
|
|
|
return Ok(vec![]);
|
|
|
|
|
}
|
|
|
|
@ -1485,7 +1486,7 @@ impl ArgMatches {
|
|
|
|
|
/// if -F/--fixed-strings is set.
|
|
|
|
|
///
|
|
|
|
|
/// If the pattern is not valid UTF-8, then an error is returned.
|
|
|
|
|
fn pattern_from_os_str(&self, pat: &OsStr) -> Result<String> {
|
|
|
|
|
fn pattern_from_os_str(&self, pat: &OsStr) -> anyhow::Result<String> {
|
|
|
|
|
let s = cli::pattern_from_os(pat)?;
|
|
|
|
|
Ok(self.pattern_from_str(s))
|
|
|
|
|
}
|
|
|
|
@ -1525,7 +1526,7 @@ impl ArgMatches {
|
|
|
|
|
/// Builds the set of globs for filtering files to apply to the --pre
|
|
|
|
|
/// flag. If no --pre-globs are available, then this always returns an
|
|
|
|
|
/// empty set of globs.
|
|
|
|
|
fn preprocessor_globs(&self) -> Result<Override> {
|
|
|
|
|
fn preprocessor_globs(&self) -> anyhow::Result<Override> {
|
|
|
|
|
let globs = self.values_of_lossy_vec("pre-glob");
|
|
|
|
|
if globs.is_empty() {
|
|
|
|
|
return Ok(Override::empty());
|
|
|
|
@ -1538,7 +1539,7 @@ impl ArgMatches {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Parse the regex-size-limit argument option into a byte count.
|
|
|
|
|
fn regex_size_limit(&self) -> Result<Option<usize>> {
|
|
|
|
|
fn regex_size_limit(&self) -> anyhow::Result<Option<usize>> {
|
|
|
|
|
let r = self.parse_human_readable_size("regex-size-limit")?;
|
|
|
|
|
u64_to_usize("regex-size-limit", r)
|
|
|
|
|
}
|
|
|
|
@ -1549,7 +1550,7 @@ impl ArgMatches {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the sorting criteria based on command line parameters.
|
|
|
|
|
fn sort_by(&self) -> Result<SortBy> {
|
|
|
|
|
fn sort_by(&self) -> anyhow::Result<SortBy> {
|
|
|
|
|
// For backcompat, continue supporting deprecated --sort-files flag.
|
|
|
|
|
if self.is_present("sort-files") {
|
|
|
|
|
return Ok(SortBy::asc(SortByKind::Path));
|
|
|
|
@ -1596,7 +1597,7 @@ impl ArgMatches {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Return the number of threads that should be used for parallelism.
|
|
|
|
|
fn threads(&self) -> Result<usize> {
|
|
|
|
|
fn threads(&self) -> anyhow::Result<usize> {
|
|
|
|
|
if self.sort_by()?.kind != SortByKind::None {
|
|
|
|
|
return Ok(1);
|
|
|
|
|
}
|
|
|
|
@ -1607,7 +1608,7 @@ impl ArgMatches {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Builds a file type matcher from the command line flags.
|
|
|
|
|
fn types(&self) -> Result<Types> {
|
|
|
|
|
fn types(&self) -> anyhow::Result<Types> {
|
|
|
|
|
let mut builder = TypesBuilder::new();
|
|
|
|
|
builder.add_defaults();
|
|
|
|
|
for ty in self.values_of_lossy_vec("type-clear") {
|
|
|
|
@ -1667,7 +1668,7 @@ impl ArgMatches {
|
|
|
|
|
///
|
|
|
|
|
/// If the number is zero, then it is considered absent and `None` is
|
|
|
|
|
/// returned.
|
|
|
|
|
fn usize_of_nonzero(&self, name: &str) -> Result<Option<usize>> {
|
|
|
|
|
fn usize_of_nonzero(&self, name: &str) -> anyhow::Result<Option<usize>> {
|
|
|
|
|
let n = match self.usize_of(name)? {
|
|
|
|
|
None => return Ok(None),
|
|
|
|
|
Some(n) => n,
|
|
|
|
@ -1677,7 +1678,7 @@ impl ArgMatches {
|
|
|
|
|
|
|
|
|
|
/// Safely reads an arg value with the given name, and if it's present,
|
|
|
|
|
/// tries to parse it as a usize value.
|
|
|
|
|
fn usize_of(&self, name: &str) -> Result<Option<usize>> {
|
|
|
|
|
fn usize_of(&self, name: &str) -> anyhow::Result<Option<usize>> {
|
|
|
|
|
match self.value_of_lossy(name) {
|
|
|
|
|
None => Ok(None),
|
|
|
|
|
Some(v) => v.parse().map(Some).map_err(From::from),
|
|
|
|
@ -1691,7 +1692,7 @@ impl ArgMatches {
|
|
|
|
|
fn parse_human_readable_size(
|
|
|
|
|
&self,
|
|
|
|
|
arg_name: &str,
|
|
|
|
|
) -> Result<Option<u64>> {
|
|
|
|
|
) -> anyhow::Result<Option<u64>> {
|
|
|
|
|
let size = match self.value_of_lossy(arg_name) {
|
|
|
|
|
None => return Ok(None),
|
|
|
|
|
Some(size) => size,
|
|
|
|
@ -1770,11 +1771,10 @@ and look-around.",
|
|
|
|
|
fn suggest_multiline(msg: String) -> String {
|
|
|
|
|
if msg.contains("the literal") && msg.contains("not allowed") {
|
|
|
|
|
format!(
|
|
|
|
|
"{}
|
|
|
|
|
"{msg}
|
|
|
|
|
|
|
|
|
|
Consider enabling multiline mode with the --multiline flag (or -U for short).
|
|
|
|
|
When multiline mode is enabled, new line characters can be matched.",
|
|
|
|
|
msg
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
msg
|
|
|
|
@ -1783,18 +1783,16 @@ When multiline mode is enabled, new line characters can be matched.",
|
|
|
|
|
|
|
|
|
|
/// Convert the result of parsing a human readable file size to a `usize`,
|
|
|
|
|
/// failing if the type does not fit.
|
|
|
|
|
fn u64_to_usize(arg_name: &str, value: Option<u64>) -> Result<Option<usize>> {
|
|
|
|
|
fn u64_to_usize(
|
|
|
|
|
arg_name: &str,
|
|
|
|
|
value: Option<u64>,
|
|
|
|
|
) -> anyhow::Result<Option<usize>> {
|
|
|
|
|
use std::usize;
|
|
|
|
|
|
|
|
|
|
let value = match value {
|
|
|
|
|
None => return Ok(None),
|
|
|
|
|
Some(value) => value,
|
|
|
|
|
};
|
|
|
|
|
if value <= usize::MAX as u64 {
|
|
|
|
|
Ok(Some(value as usize))
|
|
|
|
|
} else {
|
|
|
|
|
Err(From::from(format!("number too large for {}", arg_name)))
|
|
|
|
|
}
|
|
|
|
|
let Some(value) = value else { return Ok(None) };
|
|
|
|
|
usize::try_from(value)
|
|
|
|
|
.map_err(|_| anyhow::anyhow!("number too large for {arg_name}"))
|
|
|
|
|
.map(Some)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sorts by an optional parameter.
|
|
|
|
@ -1818,7 +1816,7 @@ fn sort_by_option<T: Ord>(
|
|
|
|
|
/// corresponds to a `--help` or `--version` request. In which case, the
|
|
|
|
|
/// corresponding output is printed and the current process is exited
|
|
|
|
|
/// successfully.
|
|
|
|
|
fn clap_matches<I, T>(args: I) -> Result<clap::ArgMatches<'static>>
|
|
|
|
|
fn clap_matches<I, T>(args: I) -> anyhow::Result<clap::ArgMatches<'static>>
|
|
|
|
|
where
|
|
|
|
|
I: IntoIterator<Item = T>,
|
|
|
|
|
T: Into<OsString> + Clone,
|
|
|
|
@ -1845,7 +1843,7 @@ where
|
|
|
|
|
/// a directory that no longer exists. We attempt some fallback mechanisms,
|
|
|
|
|
/// such as querying the PWD environment variable, but otherwise return an
|
|
|
|
|
/// error.
|
|
|
|
|
fn current_dir() -> Result<PathBuf> {
|
|
|
|
|
fn current_dir() -> anyhow::Result<PathBuf> {
|
|
|
|
|
let err = match env::current_dir() {
|
|
|
|
|
Err(err) => err,
|
|
|
|
|
Ok(cwd) => return Ok(cwd),
|
|
|
|
@ -1855,12 +1853,10 @@ fn current_dir() -> Result<PathBuf> {
|
|
|
|
|
return Ok(PathBuf::from(cwd));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Err(format!(
|
|
|
|
|
"failed to get current working directory: {} \
|
|
|
|
|
anyhow::bail!(
|
|
|
|
|
"failed to get current working directory: {err} \
|
|
|
|
|
--- did your CWD get deleted?",
|
|
|
|
|
err,
|
|
|
|
|
)
|
|
|
|
|
.into())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Retrieves the hostname that ripgrep should use wherever a hostname is
|
|
|
|
|