1
0
mirror of https://github.com/BurntSushi/ripgrep.git synced 2025-01-03 05:10:12 +02:00

cli: add --field-{context,match}-separator flags

These flags permit configuring the bytes used to delimit fields in match
or context lines, where "fields" are things like the file path, line
number, column number and the match/context itself.

Fixes #1842, Closes #1871
This commit is contained in:
Anthony Huang 2021-05-25 21:41:11 -04:00 committed by Andrew Gallant
parent 46d0130597
commit 578e1992fa
5 changed files with 151 additions and 2 deletions

View File

@ -43,6 +43,8 @@ Feature enhancements:
Cargo will now produce static executables on Windows when using MSVC.
* [FEATURE #1680](https://github.com/BurntSushi/ripgrep/pull/1680):
Add `-.` as a short flag alias for `--hidden`.
* [FEATURE #1842](https://github.com/BurntSushi/ripgrep/issues/1842):
Add `--field-{context,match}-separator` for customizing field delimiters.
* [FEATURE #1856](https://github.com/BurntSushi/ripgrep/pull/1856):
The README now links to a
[Spanish translation](https://github.com/UltiRequiem/traducciones/tree/master/ripgrep).

View File

@ -303,6 +303,8 @@ _rg() {
'--context-separator=[specify string used to separate non-continuous context lines in output]:separator'
$no"--no-context-separator[don't print context separators]"
'--debug[show debug messages]'
'--field-context-separator[set string to delimit fields in context lines]'
'--field-match-separator[set string to delimit fields in matching lines]'
'--trace[show more verbose debug messages]'
'--dfa-size-limit=[specify upper size limit of generated DFA]:DFA size (bytes)'
"(1 stats)--files[show each file that would be searched (but don't search)]"

View File

@ -568,6 +568,8 @@ pub fn all_args_and_flags() -> Vec<RGArg> {
flag_dfa_size_limit(&mut args);
flag_encoding(&mut args);
flag_engine(&mut args);
flag_field_context_separator(&mut args);
flag_field_match_separator(&mut args);
flag_file(&mut args);
flag_files(&mut args);
flag_files_with_matches(&mut args);
@ -1231,6 +1233,38 @@ This overrides previous uses of --pcre2 and --auto-hybrid-regex flags.
args.push(arg);
}
fn flag_field_context_separator(args: &mut Vec<RGArg>) {
const SHORT: &str = "Set the field context separator.";
const LONG: &str = long!(
"\
Set the field context separator, which is used to delimit file paths, line
numbers, columns and the context itself, when printing contextual lines. The
separator may be any number of bytes, including zero. Escape sequences like
\\x7F or \\t may be used. The default value is -.
"
);
let arg = RGArg::flag("field-context-separator", "SEPARATOR")
.help(SHORT)
.long_help(LONG);
args.push(arg);
}
fn flag_field_match_separator(args: &mut Vec<RGArg>) {
const SHORT: &str = "Set the match separator.";
const LONG: &str = long!(
"\
Set the field match separator, which is used to delimit file paths, line
numbers, columns and the match itself. The separator may be any number of
bytes, including zero. Escape sequences like \\x7F or \\t may be used. The
default value is -.
"
);
let arg = RGArg::flag("field-match-separator", "SEPARATOR")
.help(SHORT)
.long_help(LONG);
args.push(arg);
}
fn flag_file(args: &mut Vec<RGArg>) {
const SHORT: &str = "Search for patterns from the given file.";
const LONG: &str = long!(

View File

@ -786,8 +786,8 @@ impl ArgMatches {
.trim_ascii(self.is_present("trim"))
.separator_search(None)
.separator_context(self.context_separator())
.separator_field_match(b":".to_vec())
.separator_field_context(b"-".to_vec())
.separator_field_match(self.field_match_separator())
.separator_field_context(self.field_context_separator())
.separator_path(self.path_separator()?)
.path_terminator(self.path_terminator());
if separator_search {
@ -1377,6 +1377,24 @@ impl ArgMatches {
}
}
/// Returns the unescaped field context separator. If one wasn't specified,
/// then '-' is used as the default.
fn field_context_separator(&self) -> Vec<u8> {
match self.value_of_os("field-context-separator") {
None => b"-".to_vec(),
Some(sep) => cli::unescape_os(&sep),
}
}
/// Returns the unescaped field match separator. If one wasn't specified,
/// then ':' is used as the default.
fn field_match_separator(&self) -> Vec<u8> {
match self.value_of_os("field-match-separator") {
None => b":".to_vec(),
Some(sep) => cli::unescape_os(&sep),
}
}
/// Get a sequence of all available patterns from the command line.
/// This includes reading the -e/--regexp and -f/--file flags.
///

View File

@ -828,6 +828,99 @@ rgtest!(f1404_nothing_searched_ignored, |dir: Dir, mut cmd: TestCommand| {
eqnice!(expected, stderr);
});
// See: https://github.com/BurntSushi/ripgrep/issues/1842
rgtest!(f1842_field_context_separator, |dir: Dir, _: TestCommand| {
dir.create("sherlock", SHERLOCK);
// Test the default.
let base = &["-n", "-A1", "Doctor Watsons", "sherlock"];
let expected = "\
1:For the Doctor Watsons of this world, as opposed to the Sherlock
2-Holmeses, success in the province of detective work must always
";
eqnice!(expected, dir.command().args(base).stdout());
// Test that it can be overridden.
let mut args = vec!["--field-context-separator", "!"];
args.extend(base);
let expected = "\
1:For the Doctor Watsons of this world, as opposed to the Sherlock
2!Holmeses, success in the province of detective work must always
";
eqnice!(expected, dir.command().args(&args).stdout());
// Test that it can use multiple bytes.
let mut args = vec!["--field-context-separator", "!!"];
args.extend(base);
let expected = "\
1:For the Doctor Watsons of this world, as opposed to the Sherlock
2!!Holmeses, success in the province of detective work must always
";
eqnice!(expected, dir.command().args(&args).stdout());
// Test that unescaping works.
let mut args = vec!["--field-context-separator", r"\x7F"];
args.extend(base);
let expected = "\
1:For the Doctor Watsons of this world, as opposed to the Sherlock
2\x7FHolmeses, success in the province of detective work must always
";
eqnice!(expected, dir.command().args(&args).stdout());
// Test that an empty separator is OK.
let mut args = vec!["--field-context-separator", r""];
args.extend(base);
let expected = "\
1:For the Doctor Watsons of this world, as opposed to the Sherlock
2Holmeses, success in the province of detective work must always
";
eqnice!(expected, dir.command().args(&args).stdout());
});
// See: https://github.com/BurntSushi/ripgrep/issues/1842
rgtest!(f1842_field_match_separator, |dir: Dir, _: TestCommand| {
dir.create("sherlock", SHERLOCK);
// Test the default.
let base = &["-n", "Doctor Watsons", "sherlock"];
let expected = "\
1:For the Doctor Watsons of this world, as opposed to the Sherlock
";
eqnice!(expected, dir.command().args(base).stdout());
// Test that it can be overridden.
let mut args = vec!["--field-match-separator", "!"];
args.extend(base);
let expected = "\
1!For the Doctor Watsons of this world, as opposed to the Sherlock
";
eqnice!(expected, dir.command().args(&args).stdout());
// Test that it can use multiple bytes.
let mut args = vec!["--field-match-separator", "!!"];
args.extend(base);
let expected = "\
1!!For the Doctor Watsons of this world, as opposed to the Sherlock
";
eqnice!(expected, dir.command().args(&args).stdout());
// Test that unescaping works.
let mut args = vec!["--field-match-separator", r"\x7F"];
args.extend(base);
let expected = "\
1\x7FFor the Doctor Watsons of this world, as opposed to the Sherlock
";
eqnice!(expected, dir.command().args(&args).stdout());
// Test that an empty separator is OK.
let mut args = vec!["--field-match-separator", r""];
args.extend(base);
let expected = "\
1For the Doctor Watsons of this world, as opposed to the Sherlock
";
eqnice!(expected, dir.command().args(&args).stdout());
});
rgtest!(no_context_sep, |dir: Dir, mut cmd: TestCommand| {
dir.create("test", "foo\nctx\nbar\nctx\nfoo\nctx");
cmd.args(&["-A1", "--no-context-separator", "foo", "test"]);