From aed3ccb9c7392e3f075baa38214107dd80e9cc9e Mon Sep 17 00:00:00 2001 From: Roman Proskuryakov Date: Fri, 31 Mar 2017 00:13:07 +0300 Subject: [PATCH] Improves Printer, fixes some bugs --- src/printer.rs | 135 +++++++++++++++++++++++-------------------------- tests/tests.rs | 27 ++++++++++ 2 files changed, 89 insertions(+), 73 deletions(-) diff --git a/src/printer.rs b/src/printer.rs index 809e0d7..6667e99 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -204,22 +204,14 @@ impl Printer { pub fn path>(&mut self, path: P) { let path = strip_prefix("./", path.as_ref()).unwrap_or(path.as_ref()); self.write_path(path); - if self.null { - self.write(b"\x00"); - } else { - self.write_eol(); - } + self.write_path_eol(); } /// Prints the given path and a count of the number of matches found. pub fn path_count>(&mut self, path: P, count: u64) { if self.with_filename { self.write_path(path); - if self.null { - self.write(b"\x00"); - } else { - self.write(b":"); - } + self.write_path_sep(b':'); } self.write(count.to_string().as_bytes()); self.write_eol(); @@ -227,13 +219,11 @@ impl Printer { /// Prints the context separator. pub fn context_separate(&mut self) { - // N.B. We can't use `write` here because of borrowing restrictions. if self.context_separator.is_empty() { return; } - self.has_printed = true; let _ = self.wtr.write_all(&self.context_separator); - let _ = self.wtr.write_all(&[self.eol]); + self.write_eol(); } pub fn matched>( @@ -280,16 +270,17 @@ impl Printer { ) { if self.heading && self.with_filename && !self.has_printed { self.write_file_sep(); - self.write_heading(path.as_ref()); + self.write_path(path); + self.write_path_eol(); } else if !self.heading && self.with_filename { - self.write_non_heading_path(path.as_ref()); + self.write_path(path); + self.write_path_sep(b':'); } if let Some(line_number) = line_number { self.line_number(line_number, b':'); } if let Some(c) = column { - self.write((c + 1).to_string().as_bytes()); - self.write(b":"); + self.column_number(c + 1, b':'); } if self.replace.is_some() { let mut count = 0; @@ -299,11 +290,8 @@ impl Printer { re.replace_all(&buf[start..end], replacer) }; if self.max_columns.map_or(false, |m| line.len() > m) { - let _ = self.wtr.set_color(self.colors.matched()); - let msg = format!( - "[Omitted long line with {} replacements]", count); - self.write(msg.as_bytes()); - let _ = self.wtr.reset(); + let msg = format!("[Omitted long line with {} replacements]", count); + self.write_colored(msg.as_bytes(), |colors| colors.matched()); self.write_eol(); return; } @@ -320,10 +308,8 @@ impl Printer { fn write_matched_line(&mut self, re: &Regex, buf: &[u8]) { if self.max_columns.map_or(false, |m| buf.len() > m) { let count = re.find_iter(buf).count(); - let _ = self.wtr.set_color(self.colors.matched()); let msg = format!("[Omitted long line with {} matches]", count); - self.write(msg.as_bytes()); - let _ = self.wtr.reset(); + self.write_colored(msg.as_bytes(), |colors| colors.matched()); self.write_eol(); return; } @@ -333,9 +319,7 @@ impl Printer { let mut last_written = 0; for m in re.find_iter(buf) { self.write(&buf[last_written..m.start()]); - let _ = self.wtr.set_color(self.colors.matched()); - self.write(&buf[m.start()..m.end()]); - let _ = self.wtr.reset(); + self.write_colored(&buf[m.start()..m.end()], |colors| colors.matched()); last_written = m.end(); } self.write(&buf[last_written..]); @@ -355,14 +339,11 @@ impl Printer { ) { if self.heading && self.with_filename && !self.has_printed { self.write_file_sep(); - self.write_heading(path.as_ref()); + self.write_path(path); + self.write_path_eol(); } else if !self.heading && self.with_filename { - self.write_path(path.as_ref()); - if self.null { - self.write(b"\x00"); - } else { - self.write(b"-"); - } + self.write_path(path); + self.write_path_sep(b'-'); } if let Some(line_number) = line_number { self.line_number(line_number, b'-'); @@ -378,10 +359,19 @@ impl Printer { } } - fn write_heading>(&mut self, path: P) { - let _ = self.wtr.set_color(self.colors.path()); - self.write_path(path.as_ref()); - let _ = self.wtr.reset(); + fn separator(&mut self, sep: &[u8]) { + self.write(&sep); + } + + fn write_path_sep(&mut self, sep: u8) { + if self.null { + self.write(b"\x00"); + } else { + self.separator(&[sep]); + } + } + + fn write_path_eol(&mut self) { if self.null { self.write(b"\x00"); } else { @@ -389,52 +379,43 @@ impl Printer { } } - fn write_non_heading_path>(&mut self, path: P) { - let _ = self.wtr.set_color(self.colors.path()); - self.write_path(path.as_ref()); - let _ = self.wtr.reset(); - if self.null { - self.write(b"\x00"); - } else { - self.write(b":"); - } - } - - fn line_number(&mut self, n: u64, sep: u8) { - let _ = self.wtr.set_color(self.colors.line()); - self.write(n.to_string().as_bytes()); - let _ = self.wtr.reset(); - self.write(&[sep]); - } - #[cfg(unix)] fn write_path>(&mut self, path: P) { use std::os::unix::ffi::OsStrExt; - let path = path.as_ref().as_os_str().as_bytes(); - match self.path_separator { - None => self.write(path), - Some(sep) => self.write_path_with_sep(path, sep), - } + self.write_path_replace_separator(path); } #[cfg(not(unix))] fn write_path>(&mut self, path: P) { let path = path.as_ref().to_string_lossy(); + self.write_path_replace_separator(path.as_bytes()); + } + + fn write_path_replace_separator(&mut self, path: &[u8]) { match self.path_separator { - None => self.write(path.as_bytes()), - Some(sep) => self.write_path_with_sep(path.as_bytes(), sep), + None => self.write_colored(path, |colors| colors.path()), + Some(sep) => { + let transformed_path: Vec<_> = path.iter().map(|&b| { + if b == b'/' || (cfg!(windows) && b == b'\\') { + sep + } else { + b + } + }).collect(); + self.write_colored(&transformed_path, |colors| colors.path()); + } } } - 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 line_number(&mut self, n: u64, sep: u8) { + self.write_colored(n.to_string().as_bytes(), |colors| colors.line()); + self.separator(&[sep]); + } + + fn column_number(&mut self, n: u64, sep: u8) { + self.write(n.to_string().as_bytes()); + self.separator(&[sep]); } fn write(&mut self, buf: &[u8]) { @@ -447,6 +428,14 @@ impl Printer { self.write(&[eol]); } + fn write_colored(&mut self, buf: &[u8], get_color: F) + where F: Fn(&ColorSpecs) -> &ColorSpec + { + let _ = self.wtr.set_color( get_color(&self.colors) ); + self.write(buf); + let _ = self.wtr.reset(); + } + fn write_file_sep(&mut self) { if let Some(ref sep) = self.file_separator { self.has_printed = true; @@ -503,7 +492,7 @@ impl fmt::Display for Error { } Error::UnrecognizedStyle(ref name) => { write!(f, "Unrecognized style attribute '{}'. Choose from: \ - nobold, bold.", name) + nobold, bold, nointense, intense.", name) } Error::InvalidFormat(ref original) => { write!(f, "Invalid color speci format: '{}'. Valid format \ diff --git a/tests/tests.rs b/tests/tests.rs index 1d0964b..9457f45 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1057,6 +1057,33 @@ clean!(regression_405, "test", ".", |wd: WorkDir, mut cmd: Command| { assert_eq!(lines, format!("{}:test\n", path("bar/foo/file2.txt"))); }); +// See: https://github.com/BurntSushi/ripgrep/issues/428 +clean!(regression_428_color_context_path, "foo", ".", |wd: WorkDir, mut cmd: Command| { + wd.create("sherlock", "foo\nbar"); + cmd.arg("-A1").arg("-H").arg("--no-heading").arg("-N") + .arg("--colors=match:none").arg("--color=always"); + + let lines: String = wd.stdout(&mut cmd); + let expected = format!("\ +{colored_path}:foo +{colored_path}-bar +", colored_path=format!("\x1b\x5b\x6d\x1b\x5b\x33\x35\x6d{path}\x1b\x5b\x6d", path=path("sherlock"))); + assert_eq!(lines, expected); +}); + +// See: https://github.com/BurntSushi/ripgrep/issues/428 +clean!(regression_428_unrecognized_style, "Sherlok", ".", |wd: WorkDir, mut cmd: Command| { + cmd.arg("--colors=match:style:"); + wd.assert_err(&mut cmd); + + let output = cmd.output().unwrap(); + let err = String::from_utf8_lossy(&output.stderr); + let expected = "\ +Unrecognized style attribute ''. Choose from: nobold, bold, nointense, intense. +"; + assert_eq!(err, expected); +}); + // See: https://github.com/BurntSushi/ripgrep/issues/1 clean!(feature_1_sjis, "Шерлок Холмс", ".", |wd: WorkDir, mut cmd: Command| { let sherlock =