mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2024-12-12 19:18:24 +02:00
392bb0944a
This I believe finishes are quest to do mechanical updates to ripgrep's style, bringing it in line with my current practice (loosely speaking).
168 lines
4.5 KiB
Rust
168 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::{io::BufReadExt, ByteSlice};
|
|
|
|
/// 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,
|
|
) -> crate::Result<(Vec<OsString>, Vec<Box<dyn std::error::Error>>)> {
|
|
let path = path.as_ref();
|
|
match std::fs::File::open(&path) {
|
|
Ok(file) => parse_reader(file),
|
|
Err(err) => Err(From::from(format!("{}: {}", 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,
|
|
) -> crate::Result<(Vec<OsString>, Vec<Box<dyn std::error::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(format!("{}: {}", line_number, err).into());
|
|
}
|
|
}
|
|
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"),]);
|
|
}
|
|
}
|