summaryrefslogtreecommitdiffstats
path: root/src/handlers/grep.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/handlers/grep.rs')
-rw-r--r--src/handlers/grep.rs323
1 files changed, 251 insertions, 72 deletions
diff --git a/src/handlers/grep.rs b/src/handlers/grep.rs
index eec32c8a..f8614f7d 100644
--- a/src/handlers/grep.rs
+++ b/src/handlers/grep.rs
@@ -1,18 +1,25 @@
use std::borrow::Cow;
+use std::fmt::Write;
use lazy_static::lazy_static;
use regex::Regex;
use serde::Deserialize;
use crate::ansi;
+use crate::config::{
+ delta_unreachable, GrepType, HunkHeaderIncludeFilePath, HunkHeaderIncludeLineNumber,
+};
use crate::delta::{State, StateMachine};
use crate::handlers::{self, ripgrep_json};
use crate::paint::{self, BgShouldFill, StyleSectionSpecifier};
use crate::style::Style;
use crate::utils::{process, tabs};
+use super::hunk_header::HunkHeaderIncludeHunkLabel;
+
#[derive(Debug, PartialEq, Eq)]
pub struct GrepLine<'b> {
+ pub grep_type: GrepType,
pub path: Cow<'b, str>,
pub line_number: Option<usize>,
pub line_type: LineType,
@@ -25,6 +32,7 @@ pub struct GrepLine<'b> {
pub enum LineType {
ContextHeader,
Context,
+ FileHeader,
Match,
Ignore,
}
@@ -39,84 +47,228 @@ lazy_static! {
static ref OUTPUT_CONFIG: GrepOutputConfig = make_output_config();
}
+impl LineType {
+ fn file_path_separator(&self) -> &str {
+ // grep, rg, and git grep use ":" for matching lines
+ // and "-" for non-matching lines (and `git grep -W`
+ // uses "=" for a context header line).
+ match self {
+ LineType::Match => ":",
+ LineType::Context => "-",
+ LineType::ContextHeader => "=",
+ LineType::Ignore | LineType::FileHeader => "",
+ }
+ }
+}
+
impl<'a> StateMachine<'a> {
// If this is a line of git grep output then render it accordingly.
pub fn handle_grep_line(&mut self) -> std::io::Result<bool> {
self.painter.emit()?;
- let mut handled_line = false;
- let try_parse = matches!(&self.state, State::Grep | State::Unknown);
+ let (previous_path, previous_line_type, previous_line, try_parse) = match &self.state {
+ State::Grep(_, line_type, path, line_number) => {
+ (Some(path.clone()), Some(line_type), line_number, true)
+ }
+ State::Unknown => (None, None, &None, true),
+ _ => (None, None, &None, false),
+ };
+ let mut handled_line = false;
if try_parse {
let line = self.line.clone(); // TODO: avoid clone
- if let Some(mut grep_line) = parse_grep_line(&line) {
+ if let Some(grep_line) = parse_grep_line(&line) {
if matches!(grep_line.line_type, LineType::Ignore) {
handled_line = true;
return Ok(handled_line);
}
-
- // Emit syntax-highlighted code
- // TODO: Determine the language less frequently, e.g. only when the file changes.
- if let Some(lang) = handlers::diff_header::get_extension(&grep_line.path)
- .or(self.config.default_language.as_deref())
- {
- self.painter.set_syntax(Some(lang));
- self.painter.set_highlighter();
- }
- self.state = State::Grep;
-
- match (
- &grep_line.line_type,
- OUTPUT_CONFIG.render_context_header_as_hunk_header,
- ) {
- // Emit context header line
- (LineType::ContextHeader, true) => handlers::hunk_header::write_hunk_header(
- &grep_line.code,
- &[(grep_line.line_number.unwrap_or(0), 0)],
- &mut self.painter,
- &self.line,
- &grep_line.path,
- self.config,
- )?,
- _ => self._handle_grep_line(&mut grep_line)?,
+ let first_path = previous_path.is_none();
+ let new_path = first_path || previous_path.as_deref() != Some(&grep_line.path);
+ // Emit a '--' section separator when output contains context lines (i.e. *grep option -A, -B, -C is in effect).
+ let new_section = !new_path
+ && (previous_line_type == Some(&LineType::Context)
+ || grep_line.line_type == LineType::Context)
+ && previous_line < &grep_line.line_number.as_ref().map(|n| n - 1);
+ self.state = State::Grep(
+ self.config
+ .grep_output_type
+ .clone()
+ .unwrap_or_else(|| grep_line.grep_type.clone()),
+ grep_line.line_type,
+ grep_line.path.to_string(),
+ grep_line.line_number,
+ );
+ if new_path {
+ if let Some(lang) = handlers::diff_header::get_extension(&grep_line.path)
+ .or(self.config.default_language.as_deref())
+ {
+ self.painter.set_syntax(Some(lang));
+ self.painter.set_highlighter();
+ }
}
+ match &self.state {
+ State::Grep(GrepType::Ripgrep, _, _, _) => self.emit_ripgrep_format_grep_line(
+ grep_line,
+ new_path,
+ first_path,
+ new_section,
+ ),
+ State::Grep(GrepType::Classic, _, _, _) => {
+ self.emit_classic_format_grep_line(grep_line)
+ }
+ _ => delta_unreachable("Impossible state while handling grep line."),
+ }?;
handled_line = true
}
}
Ok(handled_line)
}
- fn _handle_grep_line(&mut self, grep_line: &mut GrepLine) -> std::io::Result<()> {
- if self.config.navigate {
- write!(
- self.painter.writer,
- "{}",
- match (
- &grep_line.line_type,
- OUTPUT_CONFIG.add_navigate_marker_to_matches
- ) {
- (LineType::Match, true) => "• ",
- (_, true) => " ",
- _ => "",
- }
+ // Emulate ripgrep output: each section of hits from the same path has a header line,
+ // and sections are separated by a blank line. Set language whenever path changes.
+ fn emit_ripgrep_format_grep_line(
+ &mut self,
+ mut grep_line: GrepLine,
+ new_path: bool,
+ first_path: bool,
+ new_section: bool,
+ ) -> std::io::Result<()> {
+ if new_path {
+ // Emit new path header line
+ if !first_path {
+ let _ = self.painter.output_buffer.write_char('\n');
+ }
+ handlers::hunk_header::write_line_of_code_with_optional_path_and_line_number(
+ "",
+ &[(0, 0)],
+ None,
+ &mut self.painter,
+ &self.line,
+ &grep_line.path,
+ self.config.ripgrep_header_style.decoration_style,
+ &self.config.grep_file_style,
+ &self.config.grep_line_number_style,
+ &HunkHeaderIncludeFilePath::Yes,
+ &HunkHeaderIncludeLineNumber::No,
+ &HunkHeaderIncludeHunkLabel::Yes,
+ "",
+ self.config,
)?
}
- self._emit_file_and_line_number(grep_line)?;
- self._emit_code(grep_line)?;
+ if new_section {
+ let _ = self.painter.output_buffer.write_str("--\n");
+ }
+ // Emit the actual grep hit line
+ let code_style_sections = match (&grep_line.line_type, &grep_line.submatches) {
+ (LineType::Match, Some(submatches)) => {
+ // We expand tabs at this late stage because
+ // the tabs are escaped in the JSON, so
+ // expansion must come after JSON parsing.
+ // (At the time of writing, we are in this
+ // arm iff we are handling `ripgrep --json`
+ // output.)
+ grep_line.code = tabs::expand(&grep_line.code, &self.config.tab_cfg).into();
+ make_style_sections(
+ &grep_line.code,
+ submatches,
+ self.config.grep_match_word_style,
+ self.config.grep_match_line_style,
+ )
+ }
+ (LineType::Match, None) => {
+ // HACK: We need tabs expanded, and we need
+ // the &str passed to
+ // `get_code_style_sections` to live long
+ // enough. But at this point it is guaranteed
+ // that this handler is going to handle this
+ // line, so mutating it is acceptable.
+ self.raw_line = tabs::expand(&self.raw_line, &self.config.tab_cfg);
+ get_code_style_sections(
+ &self.raw_line,
+ self.config.grep_match_word_style,
+ self.config.grep_match_line_style,
+ &grep_line,
+ )
+ .unwrap_or(StyleSectionSpecifier::Style(
+ self.config.grep_match_line_style,
+ ))
+ }
+ _ => StyleSectionSpecifier::Style(self.config.grep_context_line_style),
+ };
+ handlers::hunk_header::write_line_of_code_with_optional_path_and_line_number(
+ &grep_line.code,
+ &[(grep_line.line_number.unwrap_or(0), 0)],
+ Some(code_style_sections),
+ &mut self.painter,
+ &self.line,
+ &grep_line.path,
+ crate::style::DecorationStyle::NoDecoration,
+ &self.config.grep_file_style,
+ &self.config.grep_line_number_style,
+ &HunkHeaderIncludeFilePath::No,
+ if grep_line.line_number.is_some() {
+ &HunkHeaderIncludeLineNumber::Yes
+ } else {
+ &HunkHeaderIncludeLineNumber::No
+ },
+ &HunkHeaderIncludeHunkLabel::No,
+ grep_line.line_type.file_path_separator(),
+ self.config,
+ )
+ }
+
+ fn emit_classic_format_grep_line(&mut self, grep_line: GrepLine) -> std::io::Result<()> {
+ match (
+ &grep_line.line_type,
+ OUTPUT_CONFIG.render_context_header_as_hunk_header,
+ ) {
+ // Emit context header line (`git grep -W`)
+ (LineType::ContextHeader, true) => {
+ handlers::hunk_header::write_line_of_code_with_optional_path_and_line_number(
+ &grep_line.code,
+ &[(grep_line.line_number.unwrap_or(0), 0)],
+ None,
+ &mut self.painter,
+ &self.line,
+ &grep_line.path,
+ self.config.classic_grep_header_style.decoration_style,
+ &self.config.classic_grep_header_file_style,
+ &self.config.grep_line_number_style,
+ &self.config.hunk_header_style_include_file_path,
+ &self.config.hunk_header_style_include_line_number,
+ &HunkHeaderIncludeHunkLabel::Yes,
+ grep_line.line_type.file_path_separator(),
+ self.config,
+ )?
+ }
+ _ => {
+ if self.config.navigate {
+ write!(
+ self.painter.writer,
+ "{}",
+ match (
+ &grep_line.line_type,
+ OUTPUT_CONFIG.add_navigate_marker_to_matches
+ ) {
+ (LineType::Match, true) => "• ",
+ (_, true) => " ",
+ _ => "",
+ }
+ )?
+ }
+ self._emit_classic_format_file_and_line_number(&grep_line)?;
+ self._emit_classic_format_code(grep_line)?;
+ }
+ }
Ok(())
}
- fn _emit_file_and_line_number(&mut self, grep_line: &GrepLine) -> std::io::Result<()> {
+ fn _emit_classic_format_file_and_line_number(
+ &mut self,
+ grep_line: &GrepLine,
+ ) -> std::io::Result<()> {
let separator = if self.config.grep_separator_symbol == "keep" {
- // grep, rg, and git grep use ":" for matching lines
- // and "-" for non-matching lines (and `git grep -W`
- // uses "=" for a context header line).
- match grep_line.line_type {
- LineType::Match => ":",
- LineType::Context => "-",
- LineType::ContextHeader => "=",
- LineType::Ignore | LineType::FileHeader => "",
- }
+ grep_line.line_type.file_path_separator()
} else {
// But ":" results in a "file/path:number:"
// construct that terminal emulators are more likely
@@ -144,7 +296,7 @@ impl<'a> StateMachine<'a> {
Ok(())
}
- fn _emit_code(&mut self, grep_line: &mut GrepLine) -> std::io::Result<()> {
+ fn _emit_classic_format_code(&mut self, mut grep_line: GrepLine) -> std::io::Result<()> {
let code_style_sections = match (&grep_line.line_type, &grep_line.submatches) {
(LineType::Match, Some(submatches)) => {
// We expand tabs at this late stage because
@@ -153,9 +305,7 @@ impl<'a> StateMachine<'a> {
// (At the time of writing, we are in this
// arm iff we are handling `ripgrep --json`
// output.)
- grep_line.code =
- paint::expand_tabs(grep_line.code.graphemes(true), self.config.tab_width)
- .into();
+ grep_line.code = tabs::expand(&grep_line.code, &self.config.tab_cfg).into();
make_style_sections(
&grep_line.code,
submatches,
@@ -170,12 +320,12 @@ impl<'a> StateMachine<'a> {
// enough. But at the point it is guaranteed
// that this handler is going to handle this
// line, so mutating it is acceptable.
- self.raw_line = expand_tabs(self.raw_line.graphemes(true), self.config.tab_width);
+ self.raw_line = tabs::expand(&self.raw_line, &self.config.tab_cfg);
get_code_style_sections(
&self.raw_line,
self.config.grep_match_word_style,
self.config.grep_match_line_style,
- grep_line,
+ &grep_line,
)
.unwrap_or(StyleSectionSpecifier::Style(
self.config.grep_match_line_style,
@@ -278,13 +428,13 @@ fn make_output_config() -> GrepOutputConfig {
GrepOutputConfig {
render_context_header_as_hunk_header: true,
add_navigate_marker_to_matches: false,
- pad_line_number: false,
+ pad_line_number: true,
}
}
_ => GrepOutputConfig {
render_context_header_as_hunk_header: true,
add_navigate_marker_to_matches: false,
- pad_line_number: false,
+ pad_line_number: true,
},
}
}
@@ -347,8 +497,8 @@ fn make_grep_line_regex(regex_variant: GrepLineRegex) -> Regex {
( # 1. file name (colons not allowed)
[^:|\ ] # try to be strict about what a file path can start with
[^:]* # anything
- [^\ ]\.[^.\ :=-]{1,10} # extension
- )
+ [^\ ]\.[^.\ :=-]{1,10} # extension
+ )
"
}
GrepLineRegex::WithFileExtensionNoSpaces => {
@@ -356,7 +506,7 @@ fn make_grep_line_regex(regex_variant: GrepLineRegex) -> Regex {
( # 1. file name (colons not allowed)
[^:|\ ]+ # try to be strict about what a file path can start with
[^\ ]\.[^.\ :=-]{1,6} # extension
- )
+ )
"
}
GrepLineRegex::WithoutSeparatorCharacters => {
@@ -365,7 +515,7 @@ fn make_grep_line_regex(regex_variant: GrepLineRegex) -> Regex {
[^:|\ =-] # try to be strict about what a file path can start with
[^:=-]* # anything except separators
[^:\ ] # a file name cannot end with whitespace
- )
+ )
"
}
};
@@ -385,7 +535,7 @@ fn make_grep_line_regex(regex_variant: GrepLineRegex) -> Regex {
)
|
(
- = # 6. match marker
+ = # 6. context header marker
([0-9]+)= # 7. line number followed by second header marker
)
)
@@ -394,7 +544,7 @@ fn make_grep_line_regex(regex_variant: GrepLineRegex) -> Regex {
_ => {
r#"
(?:
- (
+ (
: # 2. match marker
(?:([0-9]+):)? # 3. optional: line number followed by second match marker
)
@@ -405,7 +555,7 @@ fn make_grep_line_regex(regex_variant: GrepLineRegex) -> Regex {
)
|
(
- = # 6. match marker
+ = # 6. context header marker
(?:([0-9]+)=)? # 7. optional: line number followed by second header marker
)
)
@@ -418,7 +568,7 @@ fn make_grep_line_regex(regex_variant: GrepLineRegex) -> Regex {
^
{file_path}
{separator}
-(.*) # 8. code (i.e. line contents)
+(.*) # 8. code (i.e. line contents)
$
",
))
@@ -464,6 +614,7 @@ pub fn _parse_grep_line<'b>(regex: &Regex, line: &'b str) -> Option<GrepLine<'b>
let code = caps.get(8).unwrap().as_str().into();
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: file,
line_number: *line_number,
line_type: *line_type,
@@ -474,7 +625,7 @@ pub fn _parse_grep_line<'b>(regex: &Regex, line: &'b str) -> Option<GrepLine<'b>
#[cfg(test)]
mod tests {
- use crate::handlers::grep::{parse_grep_line, GrepLine, LineType};
+ use crate::handlers::grep::{parse_grep_line, GrepLine, GrepType, LineType};
use crate::utils::process::tests::FakeParentArgs;
#[test]
@@ -485,6 +636,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/co-7-fig.rs:xxx"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/co-7-fig.rs".into(),
line_number: None,
line_type: LineType::Match,
@@ -496,6 +648,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/config.rs:use crate::minusplus::MinusPlus;"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/config.rs".into(),
line_number: None,
line_type: LineType::Match,
@@ -509,6 +662,7 @@ mod tests {
"src/config.rs: pub line_numbers_style_minusplus: MinusPlus<Style>,"
),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/config.rs".into(),
line_number: None,
line_type: LineType::Match,
@@ -520,6 +674,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/con-fig.rs:use crate::minusplus::MinusPlus;"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/con-fig.rs".into(),
line_number: None,
line_type: LineType::Match,
@@ -533,6 +688,7 @@ mod tests {
"src/con-fig.rs: pub line_numbers_style_minusplus: MinusPlus<Style>,"
),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/con-fig.rs".into(),
line_number: None,
line_type: LineType::Match,
@@ -546,7 +702,8 @@ mod tests {
"src/de lta.rs:pub fn delta<I>(lines: ByteLines<I>, writer: &mut dyn Write, config: &Config) -> std::io::Result<()>"
),
Some(GrepLine {
- path: "src/de lta.rs".into(),
+ grep_type: GrepType::Classic,
+ path: "src/de lta.rs".into(),
line_number: None,
line_type: LineType::Match,
code: "pub fn delta<I>(lines: ByteLines<I>, writer: &mut dyn Write, config: &Config) -> std::io::Result<()>".into(),
@@ -559,7 +716,8 @@ mod tests {
"src/de lta.rs: pub fn new(writer: &'a mut dyn Write, config: &'a Config) -> Self {"
),
Some(GrepLine {
- path: "src/de lta.rs".into(),
+ grep_type: GrepType::Classic,
+ path: "src/de lta.rs".into(),
line_number: None,
line_type: LineType::Match,
code: " pub fn new(writer: &'a mut dyn Write, config: &'a Config) -> Self {".into(),
@@ -577,6 +735,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/co-7-fig.rs:7:xxx"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/co-7-fig.rs".into(),
line_number: Some(7),
line_type: LineType::Match,
@@ -588,6 +747,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/config.rs:21:use crate::minusplus::MinusPlus;"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/config.rs".into(),
line_number: Some(21),
line_type: LineType::Match,
@@ -601,6 +761,7 @@ mod tests {
"src/config.rs:95: pub line_numbers_style_minusplus: MinusPlus<Style>,"
),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/config.rs".into(),
line_number: Some(95),
line_type: LineType::Match,
@@ -612,6 +773,7 @@ mod tests {
assert_eq!(
parse_grep_line("Makefile:10:test: unit-test end-to-end-test"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "Makefile".into(),
line_number: Some(10),
line_type: LineType::Match,
@@ -625,6 +787,7 @@ mod tests {
"Makefile:16: ./tests/test_raw_output_matches_git_on_full_repo_history"
),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "Makefile".into(),
line_number: Some(16),
line_type: LineType::Match,
@@ -646,6 +809,7 @@ mod tests {
assert_eq!(
parse_grep_line("etc/examples/119-within-line-edits:4:repo=$(mktemp -d)"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "etc/examples/119-within-line-edits".into(),
line_number: Some(4),
line_type: LineType::Match,
@@ -664,6 +828,7 @@ mod tests {
assert_eq!(
parse_grep_line("etc/META-INF/foo.properties:4:value=hi-there"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "etc/META-INF/foo.properties".into(),
line_number: Some(4),
line_type: LineType::Match,
@@ -682,6 +847,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/co-7-fig.rs-xxx"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/co-7-fig.rs".into(),
line_number: None,
line_type: LineType::Context,
@@ -693,6 +859,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/config.rs- pub available_terminal_width: usize,"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/config.rs".into(),
line_number: None,
line_type: LineType::Context,
@@ -704,6 +871,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/con-fig.rs-use crate::minusplus::MinusPlus;"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/con-fig.rs".into(),
line_number: None,
line_type: LineType::Context,
@@ -715,6 +883,7 @@ mod tests {
assert_eq!(
parse_grep_line("de-lta.rs- if self.source == Source::Unknown {"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "de-lta.rs".into(),
line_number: None,
line_type: LineType::Context,
@@ -726,6 +895,7 @@ mod tests {
assert_eq!(
parse_grep_line(r#"aaa/bbb.scala- s"xxx.yyy.zzz: $ccc ddd""#),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "aaa/bbb.scala".into(),
line_number: None,
line_type: LineType::Context,
@@ -737,6 +907,7 @@ mod tests {
assert_eq!(
parse_grep_line(r#"aaa/bbb.scala- val atRegex = Regex.compile("(@.*)|(-shdw@.*)""#),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "aaa/bbb.scala".into(),
line_number: None,
line_type: LineType::Context,
@@ -756,6 +927,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/co-7-fig.rs-7-xxx"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/co-7-fig.rs".into(),
line_number: Some(7),
line_type: LineType::Context,
@@ -767,6 +939,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/config.rs-58- pub available_terminal_width: usize,"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/config.rs".into(),
line_number: Some(58),
line_type: LineType::Context,
@@ -778,6 +951,7 @@ mod tests {
assert_eq!(
parse_grep_line(r#"foo.rs-12- .x-"#),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "foo.rs".into(),
line_number: Some(12),
line_type: LineType::Context,
@@ -789,6 +963,7 @@ mod tests {
assert_eq!(
parse_grep_line(r#"foo.rs-12-.x-"#),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "foo.rs".into(),
line_number: Some(12),
line_type: LineType::Context,
@@ -807,6 +982,7 @@ mod tests {
assert_eq!(
parse_grep_line("Makefile:xxx"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "Makefile".into(),
line_number: None,
line_type: LineType::Match,
@@ -825,6 +1001,7 @@ mod tests {
assert_eq!(
parse_grep_line("Makefile:7:xxx"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "Makefile".into(),
line_number: Some(7),
line_type: LineType::Match,
@@ -845,6 +1022,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/config.rs=pub struct Config {"), // match
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/config.rs".into(),
line_number: None,
line_type: LineType::ContextHeader,
@@ -865,6 +1043,7 @@ mod tests {
assert_eq!(
parse_grep_line("src/config.rs=57=pub struct Config {"),
Some(GrepLine {
+ grep_type: GrepType::Classic,
path: "src/config.rs".into(),
line_number: Some(57),
line_type: LineType::ContextHeader,