1
0
mirror of https://github.com/BurntSushi/ripgrep.git synced 2024-12-12 19:18:24 +02:00

Add --path-separator flag.

This flag permits setting the path separator used for all file paths
printed by ripgrep in normal operation.

Fixes #275
This commit is contained in:
Andrew Gallant 2017-01-10 18:16:15 -05:00
parent 2143bcf9cb
commit 8751e55706
6 changed files with 89 additions and 5 deletions

View File

@ -186,7 +186,7 @@ One byte is equal to one column.
.RS
.RE
.TP
.B \-\-context\-separator \f[I]ARG\f[]
.B \-\-context\-separator \f[I]SEPARATOR\f[]
The string to use when separating non\-continuous context lines.
Escape sequences may be used.
[default: \-\-]
@ -328,6 +328,16 @@ and \-\-files.
.RS
.RE
.TP
.B \-\-path\-separator \f[I]SEPARATOR\f[]
The path separator to use when printing file paths.
This defaults to your platform\[aq]s path separator, which is / on Unix
and \\ on Windows.
This flag is intended for overriding the default when the environment
demands it (e.g., cygwin).
A path separator is limited to a single byte.
.RS
.RE
.TP
.B \-p, \-\-pretty
Alias for \-\-color=always \-\-heading \-n.
.RS

View File

@ -128,7 +128,7 @@ Project home page: https://github.com/BurntSushi/ripgrep
numbers for the first match on each line. Note that this doesn't try
to account for Unicode. One byte is equal to one column.
--context-separator *ARG*
--context-separator *SEPARATOR*
: The string to use when separating non-continuous context lines. Escape
sequences may be used. [default: --]
@ -221,6 +221,12 @@ Project home page: https://github.com/BurntSushi/ripgrep
a list of matching files such as with --count, --files-with-matches
and --files.
--path-separator *SEPARATOR*
: The path separator to use when printing file paths. This defaults to your
platform's path separator, which is / on Unix and \\ on Windows. This flag is
intended for overriding the default when the environment demands it (e.g.,
cygwin). A path separator is limited to a single byte.
-p, --pretty
: Alias for --color=always --heading -n.

View File

@ -125,7 +125,8 @@ fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
.value_name("NUM").takes_value(true)
.validator(validate_number))
.arg(flag("column"))
.arg(flag("context-separator").value_name("ARG").takes_value(true))
.arg(flag("context-separator")
.value_name("SEPARATOR").takes_value(true))
.arg(flag("debug"))
.arg(flag("file").short("f")
.value_name("FILE").takes_value(true)
@ -154,6 +155,7 @@ fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
.arg(flag("no-ignore-parent"))
.arg(flag("no-ignore-vcs"))
.arg(flag("null"))
.arg(flag("path-separator").value_name("SEPARATOR").takes_value(true))
.arg(flag("pretty").short("p"))
.arg(flag("replace").short("r").value_name("ARG").takes_value(true))
.arg(flag("case-sensitive").short("s"))
@ -410,6 +412,13 @@ lazy_static! {
printing a list of matching files such as with --count, \
--files-with-matches and --files. This option is useful for use \
with xargs.");
doc!(h, "path-separator",
"Path separator to use when printing file paths.",
"The path separator to use when printing file paths. This \
defaults to your platform's path separator, which is / on Unix \
and \\ on Windows. This flag is intended for overriding the \
default when the environment demands it (e.g., cygwin). A path \
separator is limited to a single byte.");
doc!(h, "pretty",
"Alias for --color always --heading -n.");
doc!(h, "replace",

View File

@ -62,6 +62,7 @@ pub struct Args {
no_ignore_vcs: bool,
no_messages: bool,
null: bool,
path_separator: Option<u8>,
quiet: bool,
quiet_matched: QuietMatched,
replace: Option<Vec<u8>>,
@ -151,6 +152,7 @@ impl Args {
.heading(self.heading)
.line_per_match(self.line_per_match)
.null(self.null)
.path_separator(self.path_separator)
.with_filename(self.with_filename);
if let Some(ref rep) = self.replace {
p = p.replace(rep.clone());
@ -347,6 +349,7 @@ impl<'a> ArgMatches<'a> {
no_ignore_vcs: self.no_ignore_vcs(),
no_messages: self.is_present("no-messages"),
null: self.is_present("null"),
path_separator: try!(self.path_separator()),
quiet: quiet,
quiet_matched: QuietMatched::new(quiet),
replace: self.replace(),
@ -616,6 +619,25 @@ impl<'a> ArgMatches<'a> {
}
}
/// Returns the unescaped path separator in UTF-8 bytes.
fn path_separator(&self) -> Result<Option<u8>> {
match self.value_of_lossy("path-separator") {
None => Ok(None),
Some(sep) => {
let sep = unescape(&sep);
if sep.is_empty() {
Ok(None)
} else if sep.len() > 1 {
Err(From::from(format!(
"A path separator must be exactly one byte, but \
the given separator is {} bytes.", sep.len())))
} else {
Ok(Some(sep[0]))
}
}
}
}
/// Returns the before and after contexts from the command line.
///
/// If a context setting was absent, then `0` is returned.

View File

@ -44,6 +44,8 @@ pub struct Printer<W> {
with_filename: bool,
/// The color specifications.
colors: ColorSpecs,
/// The separator to use for file paths. If empty, this is ignored.
path_separator: Option<u8>,
}
impl<W: WriteColor> Printer<W> {
@ -62,6 +64,7 @@ impl<W: WriteColor> Printer<W> {
replace: None,
with_filename: false,
colors: ColorSpecs::default(),
path_separator: None,
}
}
@ -118,6 +121,13 @@ impl<W: WriteColor> Printer<W> {
self
}
/// A separator to use when printing file paths. When empty, use the
/// default separator for the current platform. (/ on Unix, \ on Windows.)
pub fn path_separator(mut self, sep: Option<u8>) -> Printer<W> {
self.path_separator = sep;
self
}
/// Replace every match in each matching line with the replacement string
/// given.
///
@ -342,12 +352,29 @@ impl<W: WriteColor> Printer<W> {
use std::os::unix::ffi::OsStrExt;
let path = path.as_ref().as_os_str().as_bytes();
self.write(path);
match self.path_separator {
None => self.write(path),
Some(sep) => self.write_path_with_sep(path, sep),
}
}
#[cfg(not(unix))]
fn write_path<P: AsRef<Path>>(&mut self, path: P) {
self.write(path.as_ref().to_string_lossy().as_bytes());
let path = path.as_ref().to_string_lossy();
match self.path_separator {
None => self.write(path.as_bytes()),
Some(sep) => self.write_path_with_sep(path.as_bytes(), sep),
}
}
fn write_path_with_sep(&mut self, path: &[u8], sep: u8) {
let mut path = path.to_vec();
for b in &mut path {
if *b == b'/' || (cfg!(windows) && *b == b'\\') {
*b = sep;
}
}
self.write(&path);
}
fn write(&mut self, buf: &[u8]) {

View File

@ -1226,6 +1226,16 @@ clean!(feature_263_sort_files, "test", ".", |wd: WorkDir, mut cmd: Command| {
assert_eq!(lines, "abc:test\nbar:test\nfoo:test\nzoo:test\n");
});
// See: https://github.com/BurntSushi/ripgrep/issues/275
clean!(feature_275_pathsep, "test", ".", |wd: WorkDir, mut cmd: Command| {
wd.create_dir("foo");
wd.create("foo/bar", "test");
cmd.arg("--path-separator").arg("Z");
let lines: String = wd.stdout(&mut cmd);
assert_eq!(lines, "fooZbar:test\n");
});
#[test]
fn binary_nosearch() {
let wd = WorkDir::new("binary_nosearch");