mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-04-24 17:12:16 +02:00
Add -s/--case-sensitive flag.
This flag overrides both --smart-case and --ignore-case. Closes #124.
This commit is contained in:
parent
316ffd87b3
commit
925d0db9f0
14
doc/rg.1
14
doc/rg.1
@ -70,6 +70,7 @@ Show this usage message.
|
|||||||
.TP
|
.TP
|
||||||
.B \-i, \-\-ignore\-case
|
.B \-i, \-\-ignore\-case
|
||||||
Case insensitive search.
|
Case insensitive search.
|
||||||
|
Overridden by \-\-case\-sensitive.
|
||||||
.RS
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
@ -209,6 +210,12 @@ Follow symlinks.
|
|||||||
.RS
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-maxdepth \f[I]NUM\f[]
|
||||||
|
Descend at most NUM directories below the command line arguments.
|
||||||
|
A value of zero searches only the starting\-points themselves.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
.B \-\-mmap
|
.B \-\-mmap
|
||||||
Search using memory maps when possible.
|
Search using memory maps when possible.
|
||||||
This is enabled by default when ripgrep thinks it will be faster.
|
This is enabled by default when ripgrep thinks it will be faster.
|
||||||
@ -252,9 +259,16 @@ Alias for \-\-color=always \-\-heading \-n.
|
|||||||
.RS
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
|
.B \-s, \-\-case\-sensitive
|
||||||
|
Search case sensitively.
|
||||||
|
This overrides \-\-ignore\-case and \-\-smart\-case.
|
||||||
|
.RS
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
.B \-S, \-\-smart\-case
|
.B \-S, \-\-smart\-case
|
||||||
Search case insensitively if the pattern is all lowercase.
|
Search case insensitively if the pattern is all lowercase.
|
||||||
Search case sensitively otherwise.
|
Search case sensitively otherwise.
|
||||||
|
This is overridden by either \-\-case\-sensitive or \-\-ignore\-case.
|
||||||
.RS
|
.RS
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
|
@ -49,7 +49,7 @@ the raw speed of grep.
|
|||||||
: Show this usage message.
|
: Show this usage message.
|
||||||
|
|
||||||
-i, --ignore-case
|
-i, --ignore-case
|
||||||
: Case insensitive search.
|
: Case insensitive search. Overridden by --case-sensitive.
|
||||||
|
|
||||||
-n, --line-number
|
-n, --line-number
|
||||||
: Show line numbers (1-based). This is enabled by default at a tty.
|
: Show line numbers (1-based). This is enabled by default at a tty.
|
||||||
@ -168,9 +168,13 @@ the raw speed of grep.
|
|||||||
-p, --pretty
|
-p, --pretty
|
||||||
: Alias for --color=always --heading -n.
|
: Alias for --color=always --heading -n.
|
||||||
|
|
||||||
|
-s, --case-sensitive
|
||||||
|
: Search case sensitively. This overrides --ignore-case and --smart-case.
|
||||||
|
|
||||||
-S, --smart-case
|
-S, --smart-case
|
||||||
: Search case insensitively if the pattern is all lowercase.
|
: Search case insensitively if the pattern is all lowercase.
|
||||||
Search case sensitively otherwise.
|
Search case sensitively otherwise. This is overridden by either
|
||||||
|
--case-sensitive or --ignore-case.
|
||||||
|
|
||||||
-j, --threads *ARG*
|
-j, --threads *ARG*
|
||||||
: The number of threads to use. Defaults to the number of logical CPUs
|
: The number of threads to use. Defaults to the number of logical CPUs
|
||||||
|
68
src/args.rs
68
src/args.rs
@ -62,6 +62,7 @@ Common options:
|
|||||||
Precede a glob with a '!' to exclude it.
|
Precede a glob with a '!' to exclude it.
|
||||||
-h, --help Show this usage message.
|
-h, --help Show this usage message.
|
||||||
-i, --ignore-case Case insensitive search.
|
-i, --ignore-case Case insensitive search.
|
||||||
|
Overridden by --case-sensitive.
|
||||||
-n, --line-number Show line numbers (1-based). This is enabled
|
-n, --line-number Show line numbers (1-based). This is enabled
|
||||||
by default at a tty.
|
by default at a tty.
|
||||||
-N, --no-line-number Suppress line numbers.
|
-N, --no-line-number Suppress line numbers.
|
||||||
@ -168,9 +169,13 @@ Less common options:
|
|||||||
-p, --pretty
|
-p, --pretty
|
||||||
Alias for --color=always --heading -n.
|
Alias for --color=always --heading -n.
|
||||||
|
|
||||||
|
-s, --case-sensitive
|
||||||
|
Search case sensitively. This overrides --ignore-case and --smart-case.
|
||||||
|
|
||||||
-S, --smart-case
|
-S, --smart-case
|
||||||
Search case insensitively if the pattern is all lowercase.
|
Search case insensitively if the pattern is all lowercase.
|
||||||
Search case sensitively otherwise.
|
Search case sensitively otherwise. This is overridden by
|
||||||
|
either --case-sensitive or --ignore-case.
|
||||||
|
|
||||||
-j, --threads ARG
|
-j, --threads ARG
|
||||||
The number of threads to use. Defaults to the number of logical CPUs
|
The number of threads to use. Defaults to the number of logical CPUs
|
||||||
@ -210,6 +215,7 @@ pub struct RawArgs {
|
|||||||
arg_path: Vec<String>,
|
arg_path: Vec<String>,
|
||||||
flag_after_context: usize,
|
flag_after_context: usize,
|
||||||
flag_before_context: usize,
|
flag_before_context: usize,
|
||||||
|
flag_case_sensitive: bool,
|
||||||
flag_color: String,
|
flag_color: String,
|
||||||
flag_column: bool,
|
flag_column: bool,
|
||||||
flag_context: usize,
|
flag_context: usize,
|
||||||
@ -257,7 +263,6 @@ pub struct RawArgs {
|
|||||||
/// Args are transformed/normalized from RawArgs.
|
/// Args are transformed/normalized from RawArgs.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
pattern: String,
|
|
||||||
paths: Vec<PathBuf>,
|
paths: Vec<PathBuf>,
|
||||||
after_context: usize,
|
after_context: usize,
|
||||||
before_context: usize,
|
before_context: usize,
|
||||||
@ -287,7 +292,6 @@ pub struct Args {
|
|||||||
replace: Option<Vec<u8>>,
|
replace: Option<Vec<u8>>,
|
||||||
text: bool,
|
text: bool,
|
||||||
threads: usize,
|
threads: usize,
|
||||||
type_defs: Vec<FileTypeDef>,
|
|
||||||
type_list: bool,
|
type_list: bool,
|
||||||
types: Types,
|
types: Types,
|
||||||
with_filename: bool,
|
with_filename: bool,
|
||||||
@ -296,7 +300,6 @@ pub struct Args {
|
|||||||
impl RawArgs {
|
impl RawArgs {
|
||||||
/// Convert arguments parsed into a configuration used by ripgrep.
|
/// Convert arguments parsed into a configuration used by ripgrep.
|
||||||
fn to_args(&self) -> Result<Args> {
|
fn to_args(&self) -> Result<Args> {
|
||||||
let pattern = self.pattern();
|
|
||||||
let paths =
|
let paths =
|
||||||
if self.arg_path.is_empty() {
|
if self.arg_path.is_empty() {
|
||||||
if atty::on_stdin()
|
if atty::on_stdin()
|
||||||
@ -362,7 +365,6 @@ impl RawArgs {
|
|||||||
} else {
|
} else {
|
||||||
self.flag_color == "always"
|
self.flag_color == "always"
|
||||||
};
|
};
|
||||||
let eol = b'\n';
|
|
||||||
|
|
||||||
let mut with_filename = self.flag_with_filename;
|
let mut with_filename = self.flag_with_filename;
|
||||||
if !with_filename {
|
if !with_filename {
|
||||||
@ -370,22 +372,10 @@ impl RawArgs {
|
|||||||
}
|
}
|
||||||
with_filename = with_filename && !self.flag_no_filename;
|
with_filename = with_filename && !self.flag_no_filename;
|
||||||
|
|
||||||
let mut btypes = TypesBuilder::new();
|
|
||||||
btypes.add_defaults();
|
|
||||||
try!(self.add_types(&mut btypes));
|
|
||||||
let types = try!(btypes.build());
|
|
||||||
let grep = try!(
|
|
||||||
GrepBuilder::new(&pattern)
|
|
||||||
.case_smart(self.flag_smart_case)
|
|
||||||
.case_insensitive(self.flag_ignore_case)
|
|
||||||
.line_terminator(eol)
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
let no_ignore = self.flag_no_ignore || self.flag_unrestricted >= 1;
|
let no_ignore = self.flag_no_ignore || self.flag_unrestricted >= 1;
|
||||||
let hidden = self.flag_hidden || self.flag_unrestricted >= 2;
|
let hidden = self.flag_hidden || self.flag_unrestricted >= 2;
|
||||||
let text = self.flag_text || self.flag_unrestricted >= 3;
|
let text = self.flag_text || self.flag_unrestricted >= 3;
|
||||||
let mut args = Args {
|
let mut args = Args {
|
||||||
pattern: pattern,
|
|
||||||
paths: paths,
|
paths: paths,
|
||||||
after_context: after_context,
|
after_context: after_context,
|
||||||
before_context: before_context,
|
before_context: before_context,
|
||||||
@ -394,11 +384,11 @@ impl RawArgs {
|
|||||||
context_separator: unescape(&self.flag_context_separator),
|
context_separator: unescape(&self.flag_context_separator),
|
||||||
count: self.flag_count,
|
count: self.flag_count,
|
||||||
files_with_matches: self.flag_files_with_matches,
|
files_with_matches: self.flag_files_with_matches,
|
||||||
eol: eol,
|
eol: self.eol(),
|
||||||
files: self.flag_files,
|
files: self.flag_files,
|
||||||
follow: self.flag_follow,
|
follow: self.flag_follow,
|
||||||
glob_overrides: glob_overrides,
|
glob_overrides: glob_overrides,
|
||||||
grep: grep,
|
grep: try!(self.grep()),
|
||||||
heading: !self.flag_no_heading && self.flag_heading,
|
heading: !self.flag_no_heading && self.flag_heading,
|
||||||
hidden: hidden,
|
hidden: hidden,
|
||||||
ignore_case: self.flag_ignore_case,
|
ignore_case: self.flag_ignore_case,
|
||||||
@ -419,9 +409,8 @@ impl RawArgs {
|
|||||||
replace: self.flag_replace.clone().map(|s| s.into_bytes()),
|
replace: self.flag_replace.clone().map(|s| s.into_bytes()),
|
||||||
text: text,
|
text: text,
|
||||||
threads: threads,
|
threads: threads,
|
||||||
type_defs: btypes.definitions(),
|
|
||||||
type_list: self.flag_type_list,
|
type_list: self.flag_type_list,
|
||||||
types: types,
|
types: try!(self.types()),
|
||||||
with_filename: with_filename,
|
with_filename: with_filename,
|
||||||
};
|
};
|
||||||
// If stdout is a tty, then apply some special default options.
|
// If stdout is a tty, then apply some special default options.
|
||||||
@ -440,20 +429,22 @@ impl RawArgs {
|
|||||||
Ok(args)
|
Ok(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_types(&self, types: &mut TypesBuilder) -> Result<()> {
|
fn types(&self) -> Result<Types> {
|
||||||
|
let mut btypes = TypesBuilder::new();
|
||||||
|
btypes.add_defaults();
|
||||||
for ty in &self.flag_type_clear {
|
for ty in &self.flag_type_clear {
|
||||||
types.clear(ty);
|
btypes.clear(ty);
|
||||||
}
|
}
|
||||||
for def in &self.flag_type_add {
|
for def in &self.flag_type_add {
|
||||||
try!(types.add_def(def));
|
try!(btypes.add_def(def));
|
||||||
}
|
}
|
||||||
for ty in &self.flag_type {
|
for ty in &self.flag_type {
|
||||||
types.select(ty);
|
btypes.select(ty);
|
||||||
}
|
}
|
||||||
for ty in &self.flag_type_not {
|
for ty in &self.flag_type_not {
|
||||||
types.negate(ty);
|
btypes.negate(ty);
|
||||||
}
|
}
|
||||||
Ok(())
|
btypes.build().map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pattern(&self) -> String {
|
fn pattern(&self) -> String {
|
||||||
@ -483,6 +474,27 @@ impl RawArgs {
|
|||||||
s
|
s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn eol(&self) -> u8 {
|
||||||
|
// We might want to make this configurable.
|
||||||
|
b'\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grep(&self) -> Result<Grep> {
|
||||||
|
let smart =
|
||||||
|
self.flag_smart_case
|
||||||
|
&& !self.flag_ignore_case
|
||||||
|
&& !self.flag_case_sensitive;
|
||||||
|
let casei =
|
||||||
|
self.flag_ignore_case
|
||||||
|
&& !self.flag_case_sensitive;
|
||||||
|
GrepBuilder::new(&self.pattern())
|
||||||
|
.case_smart(smart)
|
||||||
|
.case_insensitive(casei)
|
||||||
|
.line_terminator(self.eol())
|
||||||
|
.build()
|
||||||
|
.map_err(From::from)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Args {
|
impl Args {
|
||||||
@ -677,7 +689,7 @@ impl Args {
|
|||||||
|
|
||||||
/// Returns a list of type definitions currently loaded.
|
/// Returns a list of type definitions currently loaded.
|
||||||
pub fn type_defs(&self) -> &[FileTypeDef] {
|
pub fn type_defs(&self) -> &[FileTypeDef] {
|
||||||
&self.type_defs
|
self.types.definitions()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if ripgrep should print the type definitions currently
|
/// Returns true if ripgrep should print the type definitions currently
|
||||||
|
16
src/types.rs
16
src/types.rs
@ -159,6 +159,7 @@ impl FileTypeDef {
|
|||||||
/// Types is a file type matcher.
|
/// Types is a file type matcher.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Types {
|
pub struct Types {
|
||||||
|
defs: Vec<FileTypeDef>,
|
||||||
selected: Option<glob::SetYesNo>,
|
selected: Option<glob::SetYesNo>,
|
||||||
negated: Option<glob::SetYesNo>,
|
negated: Option<glob::SetYesNo>,
|
||||||
has_selected: bool,
|
has_selected: bool,
|
||||||
@ -176,8 +177,10 @@ impl Types {
|
|||||||
selected: Option<glob::SetYesNo>,
|
selected: Option<glob::SetYesNo>,
|
||||||
negated: Option<glob::SetYesNo>,
|
negated: Option<glob::SetYesNo>,
|
||||||
has_selected: bool,
|
has_selected: bool,
|
||||||
|
defs: Vec<FileTypeDef>,
|
||||||
) -> Types {
|
) -> Types {
|
||||||
Types {
|
Types {
|
||||||
|
defs: defs,
|
||||||
selected: selected,
|
selected: selected,
|
||||||
negated: negated,
|
negated: negated,
|
||||||
has_selected: has_selected,
|
has_selected: has_selected,
|
||||||
@ -193,7 +196,7 @@ impl Types {
|
|||||||
|
|
||||||
/// Creates a new file type matcher that never matches.
|
/// Creates a new file type matcher that never matches.
|
||||||
pub fn empty() -> Types {
|
pub fn empty() -> Types {
|
||||||
Types::new(None, None, false)
|
Types::new(None, None, false, vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a match for the given path against this file type matcher.
|
/// Returns a match for the given path against this file type matcher.
|
||||||
@ -233,6 +236,11 @@ impl Types {
|
|||||||
Match::None
|
Match::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the set of current file type definitions.
|
||||||
|
pub fn definitions(&self) -> &[FileTypeDef] {
|
||||||
|
&self.defs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TypesBuilder builds a type matcher from a set of file type definitions and
|
/// TypesBuilder builds a type matcher from a set of file type definitions and
|
||||||
@ -298,7 +306,11 @@ impl TypesBuilder {
|
|||||||
Some(try!(bset.build_yesno()))
|
Some(try!(bset.build_yesno()))
|
||||||
};
|
};
|
||||||
Ok(Types::new(
|
Ok(Types::new(
|
||||||
selected_globs, negated_globs, !self.selected.is_empty()))
|
selected_globs,
|
||||||
|
negated_globs,
|
||||||
|
!self.selected.is_empty(),
|
||||||
|
self.definitions(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the set of current file type definitions.
|
/// Return the set of current file type definitions.
|
||||||
|
@ -754,7 +754,8 @@ clean!(regression_105_part2, "test", ".", |wd: WorkDir, mut cmd: Command| {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See: https://github.com/BurntSushi/ripgrep/issues/20
|
// See: https://github.com/BurntSushi/ripgrep/issues/20
|
||||||
sherlock!(feature_20, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
sherlock!(feature_20_no_filename, "Sherlock", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
cmd.arg("--no-filename");
|
cmd.arg("--no-filename");
|
||||||
|
|
||||||
let lines: String = wd.stdout(&mut cmd);
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
@ -766,7 +767,7 @@ be, to a very large extent, the result of luck. Sherlock Holmes
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See: https://github.com/BurntSushi/ripgrep/issues/68
|
// See: https://github.com/BurntSushi/ripgrep/issues/68
|
||||||
clean!(feature_68, "test", ".", |wd: WorkDir, mut cmd: Command| {
|
clean!(feature_68_no_ignore_vcs, "test", ".", |wd: WorkDir, mut cmd: Command| {
|
||||||
wd.create(".gitignore", "foo");
|
wd.create(".gitignore", "foo");
|
||||||
wd.create(".ignore", "bar");
|
wd.create(".ignore", "bar");
|
||||||
wd.create("foo", "test");
|
wd.create("foo", "test");
|
||||||
@ -778,7 +779,8 @@ clean!(feature_68, "test", ".", |wd: WorkDir, mut cmd: Command| {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See: https://github.com/BurntSushi/ripgrep/issues/70
|
// See: https://github.com/BurntSushi/ripgrep/issues/70
|
||||||
sherlock!(feature_70, "sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
sherlock!(feature_70_smart_case, "sherlock", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
cmd.arg("--smart-case");
|
cmd.arg("--smart-case");
|
||||||
|
|
||||||
let lines: String = wd.stdout(&mut cmd);
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
@ -832,7 +834,7 @@ sherlock\x00can extract a clew from a wisp of straw or a flake of cigar ash;
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See: https://github.com/BurntSushi/ripgrep/issues/109
|
// See: https://github.com/BurntSushi/ripgrep/issues/109
|
||||||
clean!(max_depth, "far", ".", |wd: WorkDir, mut cmd: Command| {
|
clean!(feature_109_max_depth, "far", ".", |wd: WorkDir, mut cmd: Command| {
|
||||||
wd.create_dir("one");
|
wd.create_dir("one");
|
||||||
wd.create("one/pass", "far");
|
wd.create("one/pass", "far");
|
||||||
wd.create_dir("one/too");
|
wd.create_dir("one/too");
|
||||||
@ -842,10 +844,25 @@ clean!(max_depth, "far", ".", |wd: WorkDir, mut cmd: Command| {
|
|||||||
|
|
||||||
let lines: String = wd.stdout(&mut cmd);
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
let expected = path("one/pass:far\n");
|
let expected = path("one/pass:far\n");
|
||||||
|
|
||||||
assert_eq!(lines, expected);
|
assert_eq!(lines, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/124
|
||||||
|
clean!(feature_109_case_sensitive_part1, "test", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
|
wd.create("foo", "tEsT");
|
||||||
|
cmd.arg("--smart-case").arg("--case-sensitive");
|
||||||
|
wd.assert_err(&mut cmd);
|
||||||
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/124
|
||||||
|
clean!(feature_109_case_sensitive_part2, "test", ".",
|
||||||
|
|wd: WorkDir, mut cmd: Command| {
|
||||||
|
wd.create("foo", "tEsT");
|
||||||
|
cmd.arg("--ignore-case").arg("--case-sensitive");
|
||||||
|
wd.assert_err(&mut cmd);
|
||||||
|
});
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn binary_nosearch() {
|
fn binary_nosearch() {
|
||||||
let wd = WorkDir::new("binary_nosearch");
|
let wd = WorkDir::new("binary_nosearch");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user