mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-11-23 21:54:45 +02:00
Maybe 2024 changes? Note that we now set `edition = "2024"` explicitly in `rustfmt.toml`. Without this, it seems like it's possible in some cases for rustfmt to run under an older edition's style. Not sure how though.
171 lines
4.5 KiB
Rust
171 lines
4.5 KiB
Rust
/*!
|
|
This module provides routines for reading ripgrep config "rc" files.
|
|
|
|
The primary output of these routines is a sequence of arguments, where each
|
|
argument corresponds precisely to one shell argument.
|
|
*/
|
|
|
|
use std::{
|
|
ffi::OsString,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use bstr::{ByteSlice, io::BufReadExt};
|
|
|
|
/// Return a sequence of arguments derived from ripgrep rc configuration files.
|
|
pub fn args() -> Vec<OsString> {
|
|
let config_path = match std::env::var_os("RIPGREP_CONFIG_PATH") {
|
|
None => return vec![],
|
|
Some(config_path) => {
|
|
if config_path.is_empty() {
|
|
return vec![];
|
|
}
|
|
PathBuf::from(config_path)
|
|
}
|
|
};
|
|
let (args, errs) = match parse(&config_path) {
|
|
Ok((args, errs)) => (args, errs),
|
|
Err(err) => {
|
|
message!(
|
|
"failed to read the file specified in RIPGREP_CONFIG_PATH: {}",
|
|
err
|
|
);
|
|
return vec![];
|
|
}
|
|
};
|
|
if !errs.is_empty() {
|
|
for err in errs {
|
|
message!("{}:{}", config_path.display(), err);
|
|
}
|
|
}
|
|
log::debug!(
|
|
"{}: arguments loaded from config file: {:?}",
|
|
config_path.display(),
|
|
args
|
|
);
|
|
args
|
|
}
|
|
|
|
/// Parse a single ripgrep rc file from the given path.
|
|
///
|
|
/// On success, this returns a set of shell arguments, in order, that should
|
|
/// be pre-pended to the arguments given to ripgrep at the command line.
|
|
///
|
|
/// If the file could not be read, then an error is returned. If there was
|
|
/// a problem parsing one or more lines in the file, then errors are returned
|
|
/// for each line in addition to successfully parsed arguments.
|
|
fn parse<P: AsRef<Path>>(
|
|
path: P,
|
|
) -> anyhow::Result<(Vec<OsString>, Vec<anyhow::Error>)> {
|
|
let path = path.as_ref();
|
|
match std::fs::File::open(&path) {
|
|
Ok(file) => parse_reader(file),
|
|
Err(err) => anyhow::bail!("{}: {}", path.display(), err),
|
|
}
|
|
}
|
|
|
|
/// Parse a single ripgrep rc file from the given reader.
|
|
///
|
|
/// Callers should not provided a buffered reader, as this routine will use its
|
|
/// own buffer internally.
|
|
///
|
|
/// On success, this returns a set of shell arguments, in order, that should
|
|
/// be pre-pended to the arguments given to ripgrep at the command line.
|
|
///
|
|
/// If the reader could not be read, then an error is returned. If there was a
|
|
/// problem parsing one or more lines, then errors are returned for each line
|
|
/// in addition to successfully parsed arguments.
|
|
fn parse_reader<R: std::io::Read>(
|
|
rdr: R,
|
|
) -> anyhow::Result<(Vec<OsString>, Vec<anyhow::Error>)> {
|
|
let mut bufrdr = std::io::BufReader::new(rdr);
|
|
let (mut args, mut errs) = (vec![], vec![]);
|
|
let mut line_number = 0;
|
|
bufrdr.for_byte_line_with_terminator(|line| {
|
|
line_number += 1;
|
|
|
|
let line = line.trim();
|
|
if line.is_empty() || line[0] == b'#' {
|
|
return Ok(true);
|
|
}
|
|
match line.to_os_str() {
|
|
Ok(osstr) => {
|
|
args.push(osstr.to_os_string());
|
|
}
|
|
Err(err) => {
|
|
errs.push(anyhow::anyhow!("{line_number}: {err}"));
|
|
}
|
|
}
|
|
Ok(true)
|
|
})?;
|
|
Ok((args, errs))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::parse_reader;
|
|
use std::ffi::OsString;
|
|
|
|
#[test]
|
|
fn basic() {
|
|
let (args, errs) = parse_reader(
|
|
&b"\
|
|
# Test
|
|
--context=0
|
|
--smart-case
|
|
-u
|
|
|
|
|
|
# --bar
|
|
--foo
|
|
"[..],
|
|
)
|
|
.unwrap();
|
|
assert!(errs.is_empty());
|
|
let args: Vec<String> =
|
|
args.into_iter().map(|s| s.into_string().unwrap()).collect();
|
|
assert_eq!(args, vec!["--context=0", "--smart-case", "-u", "--foo",]);
|
|
}
|
|
|
|
// We test that we can handle invalid UTF-8 on Unix-like systems.
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn error() {
|
|
use std::os::unix::ffi::OsStringExt;
|
|
|
|
let (args, errs) = parse_reader(
|
|
&b"\
|
|
quux
|
|
foo\xFFbar
|
|
baz
|
|
"[..],
|
|
)
|
|
.unwrap();
|
|
assert!(errs.is_empty());
|
|
assert_eq!(
|
|
args,
|
|
vec![
|
|
OsString::from("quux"),
|
|
OsString::from_vec(b"foo\xFFbar".to_vec()),
|
|
OsString::from("baz"),
|
|
]
|
|
);
|
|
}
|
|
|
|
// ... but test that invalid UTF-8 fails on Windows.
|
|
#[test]
|
|
#[cfg(not(unix))]
|
|
fn error() {
|
|
let (args, errs) = parse_reader(
|
|
&b"\
|
|
quux
|
|
foo\xFFbar
|
|
baz
|
|
"[..],
|
|
)
|
|
.unwrap();
|
|
assert_eq!(errs.len(), 1);
|
|
assert_eq!(args, vec![OsString::from("quux"), OsString::from("baz"),]);
|
|
}
|
|
}
|