mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2024-12-12 19:18:24 +02:00
fdd8510fdd
The top-level listing was just getting a bit too long for my taste. So put all of the code in one directory and shrink the large top-level mess to a small top-level mess. NOTE: This commit only contains renames. The subsequent commit will actually make ripgrep build again. We do it this way with the naive hope that this will make it easier for git history to track the renames. Sigh.
170 lines
4.4 KiB
Rust
170 lines
4.4 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::env;
|
|
use std::error::Error;
|
|
use std::ffi::OsString;
|
|
use std::fs::File;
|
|
use std::io;
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use bstr::{io::BufReadExt, ByteSlice};
|
|
use log;
|
|
|
|
use crate::Result;
|
|
|
|
/// Return a sequence of arguments derived from ripgrep rc configuration files.
|
|
pub fn args() -> Vec<OsString> {
|
|
let config_path = match 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!("{}", 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,
|
|
) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
|
|
let path = path.as_ref();
|
|
match 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: io::Read>(
|
|
rdr: R,
|
|
) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
|
|
let bufrdr = 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"),]);
|
|
}
|
|
}
|