mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-10-06 05:36:58 +02:00
colors: add highlight
type support for matching lines
This lets users highlight non-matching text in matching lines. Closes #3024, Closes #3107
This commit is contained in:
committed by
Andrew Gallant
parent
126bbeab8c
commit
99fe884536
@@ -43,6 +43,8 @@ Feature enhancements:
|
|||||||
When using multithreading, schedule files to search in order given on CLI.
|
When using multithreading, schedule files to search in order given on CLI.
|
||||||
* [FEATURE #2943](https://github.com/BurntSushi/ripgrep/issues/2943):
|
* [FEATURE #2943](https://github.com/BurntSushi/ripgrep/issues/2943):
|
||||||
Add `aarch64` release artifacts for Windows.
|
Add `aarch64` release artifacts for Windows.
|
||||||
|
* [FEATURE #3024](https://github.com/BurntSushi/ripgrep/issues/3024):
|
||||||
|
Add `highlight` color type, for styling non-matching text in a matching line.
|
||||||
* [FEATURE #3048](https://github.com/BurntSushi/ripgrep/pull/3048):
|
* [FEATURE #3048](https://github.com/BurntSushi/ripgrep/pull/3048):
|
||||||
Globs in ripgrep (and the `globset` crate) now support nested alternates.
|
Globs in ripgrep (and the `globset` crate) now support nested alternates.
|
||||||
|
|
||||||
|
4
FAQ.md
4
FAQ.md
@@ -285,8 +285,8 @@ As a special case, `--colors '{type}:none'` will clear all colors and styles
|
|||||||
associated with `{type}`, which lets you start with a clean slate (instead of
|
associated with `{type}`, which lets you start with a clean slate (instead of
|
||||||
building on top of ripgrep's default color settings).
|
building on top of ripgrep's default color settings).
|
||||||
|
|
||||||
Here's an example that makes highlights the matches with a nice blue background
|
Here's an example that highlights the matches with a nice blue background with
|
||||||
with bolded white text:
|
bolded white text:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rg somepattern \
|
$ rg somepattern \
|
||||||
|
@@ -363,10 +363,11 @@ _rg() {
|
|||||||
'column:specify coloring for column numbers'
|
'column:specify coloring for column numbers'
|
||||||
'line:specify coloring for line numbers'
|
'line:specify coloring for line numbers'
|
||||||
'match:specify coloring for match text'
|
'match:specify coloring for match text'
|
||||||
|
'highlight:specify coloring for matching lines'
|
||||||
'path:specify coloring for file names'
|
'path:specify coloring for file names'
|
||||||
)
|
)
|
||||||
descr='color/style type'
|
descr='color/style type'
|
||||||
elif [[ ${IPREFIX#--*=}$PREFIX == (column|line|match|path):[^:]# ]]; then
|
elif [[ ${IPREFIX#--*=}$PREFIX == (column|line|match|highlight|path):[^:]# ]]; then
|
||||||
suf=( -qS: )
|
suf=( -qS: )
|
||||||
tmp=(
|
tmp=(
|
||||||
'none:clear color/style for type'
|
'none:clear color/style for type'
|
||||||
|
@@ -751,7 +751,8 @@ the \flag{colors} flag to manually set all color styles to \fBnone\fP:
|
|||||||
\-\-colors 'path:none' \\
|
\-\-colors 'path:none' \\
|
||||||
\-\-colors 'line:none' \\
|
\-\-colors 'line:none' \\
|
||||||
\-\-colors 'column:none' \\
|
\-\-colors 'column:none' \\
|
||||||
\-\-colors 'match:none'
|
\-\-colors 'match:none' \\
|
||||||
|
\-\-colors 'highlight:none'
|
||||||
.EE
|
.EE
|
||||||
.sp
|
.sp
|
||||||
"
|
"
|
||||||
@@ -829,7 +830,7 @@ impl Flag for Colors {
|
|||||||
"Configure color settings and styles."
|
"Configure color settings and styles."
|
||||||
}
|
}
|
||||||
fn doc_long(&self) -> &'static str {
|
fn doc_long(&self) -> &'static str {
|
||||||
r"
|
r#"
|
||||||
This flag specifies color settings for use in the output. This flag may be
|
This flag specifies color settings for use in the output. This flag may be
|
||||||
provided multiple times. Settings are applied iteratively. Pre-existing color
|
provided multiple times. Settings are applied iteratively. Pre-existing color
|
||||||
labels are limited to one of eight choices: \fBred\fP, \fBblue\fP, \fBgreen\fP,
|
labels are limited to one of eight choices: \fBred\fP, \fBblue\fP, \fBgreen\fP,
|
||||||
@@ -839,11 +840,11 @@ are limited to \fBnobold\fP, \fBbold\fP, \fBnointense\fP, \fBintense\fP,
|
|||||||
.sp
|
.sp
|
||||||
The format of the flag is
|
The format of the flag is
|
||||||
\fB{\fP\fItype\fP\fB}:{\fP\fIattribute\fP\fB}:{\fP\fIvalue\fP\fB}\fP.
|
\fB{\fP\fItype\fP\fB}:{\fP\fIattribute\fP\fB}:{\fP\fIvalue\fP\fB}\fP.
|
||||||
\fItype\fP should be one of \fBpath\fP, \fBline\fP, \fBcolumn\fP or
|
\fItype\fP should be one of \fBpath\fP, \fBline\fP, \fBcolumn\fP,
|
||||||
\fBmatch\fP. \fIattribute\fP can be \fBfg\fP, \fBbg\fP or \fBstyle\fP.
|
\fBhighlight\fP or \fBmatch\fP. \fIattribute\fP can be \fBfg\fP, \fBbg\fP or
|
||||||
\fIvalue\fP is either a color (for \fBfg\fP and \fBbg\fP) or a text style. A
|
\fBstyle\fP. \fIvalue\fP is either a color (for \fBfg\fP and \fBbg\fP) or a
|
||||||
special format, \fB{\fP\fItype\fP\fB}:none\fP, will clear all color settings
|
text style. A special format, \fB{\fP\fItype\fP\fB}:none\fP, will clear all
|
||||||
for \fItype\fP.
|
color settings for \fItype\fP.
|
||||||
.sp
|
.sp
|
||||||
For example, the following command will change the match color to magenta and
|
For example, the following command will change the match color to magenta and
|
||||||
the background color for line numbers to yellow:
|
the background color for line numbers to yellow:
|
||||||
@@ -852,6 +853,17 @@ the background color for line numbers to yellow:
|
|||||||
rg \-\-colors 'match:fg:magenta' \-\-colors 'line:bg:yellow'
|
rg \-\-colors 'match:fg:magenta' \-\-colors 'line:bg:yellow'
|
||||||
.EE
|
.EE
|
||||||
.sp
|
.sp
|
||||||
|
Another example, the following command will "highlight" the non-matching text
|
||||||
|
in matching lines:
|
||||||
|
.sp
|
||||||
|
.EX
|
||||||
|
rg \-\-colors 'highlight:bg:yellow' \-\-colors 'highlight:fg:black'
|
||||||
|
.EE
|
||||||
|
.sp
|
||||||
|
The "highlight" color type is particularly useful for contrasting matching
|
||||||
|
lines with surrounding context printed by the \flag{before-context},
|
||||||
|
\flag{after-context}, \flag{context} or \flag{passthru} flags.
|
||||||
|
.sp
|
||||||
Extended colors can be used for \fIvalue\fP when the tty supports ANSI color
|
Extended colors can be used for \fIvalue\fP when the tty supports ANSI color
|
||||||
sequences. These are specified as either \fIx\fP (256-color) or
|
sequences. These are specified as either \fIx\fP (256-color) or
|
||||||
.IB x , x , x
|
.IB x , x , x
|
||||||
@@ -874,7 +886,7 @@ or, equivalently,
|
|||||||
.sp
|
.sp
|
||||||
Note that the \fBintense\fP and \fBnointense\fP styles will have no effect when
|
Note that the \fBintense\fP and \fBnointense\fP styles will have no effect when
|
||||||
used alongside these extended color codes.
|
used alongside these extended color codes.
|
||||||
"
|
"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
||||||
@@ -908,6 +920,24 @@ fn test_colors() {
|
|||||||
"line:bg:yellow".parse().unwrap()
|
"line:bg:yellow".parse().unwrap()
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let args = parse_low_raw(["--colors", "highlight:bg:240"]).unwrap();
|
||||||
|
assert_eq!(args.colors, vec!["highlight:bg:240".parse().unwrap()]);
|
||||||
|
|
||||||
|
let args = parse_low_raw([
|
||||||
|
"--colors",
|
||||||
|
"match:fg:magenta",
|
||||||
|
"--colors",
|
||||||
|
"highlight:bg:blue",
|
||||||
|
])
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
args.colors,
|
||||||
|
vec![
|
||||||
|
"match:fg:magenta".parse().unwrap(),
|
||||||
|
"highlight:bg:blue".parse().unwrap()
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// --column
|
/// --column
|
||||||
|
@@ -51,13 +51,13 @@ impl std::fmt::Display for ColorError {
|
|||||||
ColorError::UnrecognizedOutType(ref name) => write!(
|
ColorError::UnrecognizedOutType(ref name) => write!(
|
||||||
f,
|
f,
|
||||||
"unrecognized output type '{}'. Choose from: \
|
"unrecognized output type '{}'. Choose from: \
|
||||||
path, line, column, match.",
|
path, line, column, match, highlight.",
|
||||||
name,
|
name,
|
||||||
),
|
),
|
||||||
ColorError::UnrecognizedSpecType(ref name) => write!(
|
ColorError::UnrecognizedSpecType(ref name) => write!(
|
||||||
f,
|
f,
|
||||||
"unrecognized spec type '{}'. Choose from: \
|
"unrecognized spec type '{}'. Choose from: \
|
||||||
fg, bg, style, none.",
|
fg, bg, style, none.",
|
||||||
name,
|
name,
|
||||||
),
|
),
|
||||||
ColorError::UnrecognizedColor(_, ref msg) => write!(f, "{}", msg),
|
ColorError::UnrecognizedColor(_, ref msg) => write!(f, "{}", msg),
|
||||||
@@ -70,8 +70,8 @@ impl std::fmt::Display for ColorError {
|
|||||||
),
|
),
|
||||||
ColorError::InvalidFormat(ref original) => write!(
|
ColorError::InvalidFormat(ref original) => write!(
|
||||||
f,
|
f,
|
||||||
"invalid color spec format: '{}'. Valid format \
|
"invalid color spec format: '{}'. Valid format is \
|
||||||
is '(path|line|column|match):(fg|bg|style):(value)'.",
|
'(path|line|column|match|highlight):(fg|bg|style):(value)'.",
|
||||||
original,
|
original,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@@ -90,6 +90,7 @@ pub struct ColorSpecs {
|
|||||||
line: ColorSpec,
|
line: ColorSpec,
|
||||||
column: ColorSpec,
|
column: ColorSpec,
|
||||||
matched: ColorSpec,
|
matched: ColorSpec,
|
||||||
|
highlight: ColorSpec,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single color specification provided by the user.
|
/// A single color specification provided by the user.
|
||||||
@@ -99,7 +100,7 @@ pub struct ColorSpecs {
|
|||||||
/// The format of a `Spec` is a triple: `{type}:{attribute}:{value}`. Each
|
/// The format of a `Spec` is a triple: `{type}:{attribute}:{value}`. Each
|
||||||
/// component is defined as follows:
|
/// component is defined as follows:
|
||||||
///
|
///
|
||||||
/// * `{type}` can be one of `path`, `line`, `column` or `match`.
|
/// * `{type}` can be one of `path`, `line`, `column`, `match` or `highlight`.
|
||||||
/// * `{attribute}` can be one of `fg`, `bg` or `style`. `{attribute}` may also
|
/// * `{attribute}` can be one of `fg`, `bg` or `style`. `{attribute}` may also
|
||||||
/// be the special value `none`, in which case, `{value}` can be omitted.
|
/// be the special value `none`, in which case, `{value}` can be omitted.
|
||||||
/// * `{value}` is either a color name (for `fg`/`bg`) or a style instruction.
|
/// * `{value}` is either a color name (for `fg`/`bg`) or a style instruction.
|
||||||
@@ -181,6 +182,7 @@ enum OutType {
|
|||||||
Line,
|
Line,
|
||||||
Column,
|
Column,
|
||||||
Match,
|
Match,
|
||||||
|
Highlight,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The specification type.
|
/// The specification type.
|
||||||
@@ -216,6 +218,7 @@ impl ColorSpecs {
|
|||||||
OutType::Line => spec.merge_into(&mut merged.line),
|
OutType::Line => spec.merge_into(&mut merged.line),
|
||||||
OutType::Column => spec.merge_into(&mut merged.column),
|
OutType::Column => spec.merge_into(&mut merged.column),
|
||||||
OutType::Match => spec.merge_into(&mut merged.matched),
|
OutType::Match => spec.merge_into(&mut merged.matched),
|
||||||
|
OutType::Highlight => spec.merge_into(&mut merged.highlight),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
merged
|
merged
|
||||||
@@ -249,6 +252,12 @@ impl ColorSpecs {
|
|||||||
pub fn matched(&self) -> &ColorSpec {
|
pub fn matched(&self) -> &ColorSpec {
|
||||||
&self.matched
|
&self.matched
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the color specification for coloring entire line if there is a
|
||||||
|
/// matched text.
|
||||||
|
pub fn highlight(&self) -> &ColorSpec {
|
||||||
|
&self.highlight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserColorSpec {
|
impl UserColorSpec {
|
||||||
@@ -348,6 +357,7 @@ impl std::str::FromStr for OutType {
|
|||||||
"line" => Ok(OutType::Line),
|
"line" => Ok(OutType::Line),
|
||||||
"column" => Ok(OutType::Column),
|
"column" => Ok(OutType::Column),
|
||||||
"match" => Ok(OutType::Match),
|
"match" => Ok(OutType::Match),
|
||||||
|
"highlight" => Ok(OutType::Highlight),
|
||||||
_ => Err(ColorError::UnrecognizedOutType(s.to_string())),
|
_ => Err(ColorError::UnrecognizedOutType(s.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1320,6 +1320,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
self.write(&bytes[line])?;
|
self.write(&bytes[line])?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
self.start_line_highlight()?;
|
||||||
while !line.is_empty() {
|
while !line.is_empty() {
|
||||||
if matches[*match_index].end() <= line.start() {
|
if matches[*match_index].end() <= line.start() {
|
||||||
if *match_index + 1 < matches.len() {
|
if *match_index + 1 < matches.len() {
|
||||||
@@ -1346,6 +1347,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.end_color_match()?;
|
self.end_color_match()?;
|
||||||
|
self.end_line_highlight()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1547,11 +1549,37 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
if !self.in_color_match.get() {
|
if !self.in_color_match.get() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.wtr().borrow_mut().reset()?;
|
if self.highlight_on() {
|
||||||
|
self.wtr()
|
||||||
|
.borrow_mut()
|
||||||
|
.set_color(self.config().colors.highlight())?;
|
||||||
|
} else {
|
||||||
|
self.wtr().borrow_mut().reset()?;
|
||||||
|
}
|
||||||
self.in_color_match.set(false);
|
self.in_color_match.set(false);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn highlight_on(&self) -> bool {
|
||||||
|
!self.config().colors.highlight().is_none() && !self.is_context()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_line_highlight(&self) -> io::Result<()> {
|
||||||
|
if self.highlight_on() {
|
||||||
|
self.wtr()
|
||||||
|
.borrow_mut()
|
||||||
|
.set_color(self.config().colors.highlight())?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_line_highlight(&self) -> io::Result<()> {
|
||||||
|
if self.highlight_on() {
|
||||||
|
self.wtr().borrow_mut().reset()?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> io::Result<()> {
|
fn write(&self, buf: &[u8]) -> io::Result<()> {
|
||||||
self.wtr().borrow_mut().write_all(buf)
|
self.wtr().borrow_mut().write_all(buf)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user