Match highlighting and better colors in report

This commit is contained in:
Cameron Cordes
2020-05-19 15:17:09 -04:00
parent b73e4d38f1
commit e1aa96dd78
3 changed files with 254 additions and 13 deletions

View File

@@ -1,31 +1,130 @@
use std::env;
use std::io;
use std::fs::{self};
use std::path::Path;
extern crate term;
mod config;
fn main() {
let config = config::Config::from_args();
println!("{:?}", config);
let path = Path::new(".");
traverse_dir(path);
let results = traverse_dir(&config, path, |config, path| check_file(config, path));
match results {
Result::Ok(matches) if matches.len() == 0 => println!("No matches :("),
Result::Ok(matches) => print_report(&matches),
Result::Err(msg) => println!("Error while parsing: {}", msg)
}
}
fn parse_args() {
fn traverse_dir(config: &config::Config, dir: &Path, operation: fn(&config::Config, &Path) -> io::Result<FileMatch>)
-> io::Result<Vec<FileMatch>> {
let mut matches: Vec<FileMatch> = Vec::new();
for entry in fs::read_dir(dir)? {
let entry = entry?;
let file_type = entry.file_type()?;
if file_type.is_dir() {
let results = traverse_dir(&config, &entry.path(), operation)?;
for mat in results.as_slice() {
if mat.matches.len() > 0 {
matches.append(&mut results.clone());
}
}
} else {
let result = operation(&config, &entry.path());
match result {
Result::Ok(result) if result.matches.len() > 0 => matches.push(result),
_ => ()
}
}
}
Ok(matches)
}
#[derive(Debug, Clone)]
struct FileMatch {
file_name: String,
matches: Vec<Match>
}
fn traverse_dir(dir: &Path) -> io::Result<()> {
for entry in fs::read_dir(dir)? {
let entry = entry?;
let file_type = entry.file_type()?;
impl FileMatch {
fn print(&self) {
let mut term = term::stdout().unwrap();
term.fg(term::color::YELLOW).unwrap();
term.attr(term::Attr::Bold).unwrap();
println!("{}:", self.file_name);
term.reset().unwrap();
if file_type.is_dir() {
traverse_dir(&entry.path());
for mat in &self.matches {
term.attr(term::Attr::Bold).unwrap();
print!("{}: ", mat.line_number);
term.reset().unwrap();
let mut last_position = 0;
for (idx, match_index) in mat.match_indexes.iter().enumerate() {
print!("{}", mat.text.get(last_position..match_index.start).unwrap());
term.fg(term::color::BRIGHT_RED).unwrap();
print!("{}", mat.text.get(match_index.start..match_index.end).unwrap());
term.reset().unwrap();
if idx == mat.match_indexes.len() -1 {
println!("{}", mat.text.get(match_index.end..mat.text.len()).unwrap());
last_position = 0;
} else {
last_position = match_index.end;
}
}
}
println!();
}
}
#[derive(Debug, Clone)]
struct Match {
line_number: usize,
match_indexes: Vec<MatchIndex>,
text: String
}
#[derive(Debug, Clone)]
struct MatchIndex {
start: usize,
end: usize
}
fn check_file(config: &config::Config, path: &Path) -> io::Result<FileMatch> {
let pattern = &config.pattern;
// TODO: Use BufRead and read_line instead of reading the entire file into memory.
let content = fs::read_to_string(&path)?;
let mut matches = Vec::new();
for (number, line) in content.lines().enumerate() {
if line.contains(pattern) {
let mut indexes = Vec::<MatchIndex>::new();
for m in line.trim().match_indices(pattern) {
indexes.push(MatchIndex { start: m.0, end: m.0 + pattern.len() });
}
matches.push(Match { line_number: number + 1, text: line.trim().to_string(), match_indexes: indexes });
}
}
Ok(())
Ok(FileMatch { file_name: path.to_str().unwrap().to_string(), matches: matches })
}
fn print_report(matches: &Vec<FileMatch>) {
for file in matches {
file.print()
// println!("{}:", file.file_name);
// for mat in &file.matches {
// println!("{}", mat.text);
// }
// println!();
}
}