Files
Rack/src/main.rs
Cameron Cordes 276db68727 Fix lint issues
2020-05-22 16:17:03 -04:00

147 lines
4.5 KiB
Rust

use rack::config::Config;
use rack::filematch::*;
use std::fs::{self, DirEntry, File};
use std::io;
use std::io::prelude::*;
use std::path::Path;
extern crate term;
fn main() {
let config = Config::from_args();
let search_path = &config.path;
let path = if search_path.starts_with('/') {
Path::new(search_path)
} else {
let p: &'static str = Box::leak(Box::new(String::from("./") + search_path));
Path::new(p)
};
let results = traverse_dir(&config, path, Option::None, |config, path| {
check_file(config, path)
});
match results {
Result::Ok(matches) if matches.is_empty() => println!("No matches :("),
Result::Ok(matches) => print_report(&config, &matches),
Result::Err(msg) => println!("Error while parsing: {}", msg),
}
}
fn traverse_dir(
config: &Config,
dir: &Path,
gitignore_entries: Option<Vec<String>>,
operation: fn(&Config, &Path) -> io::Result<FileMatch>,
) -> io::Result<Vec<FileMatch>> {
let mut matches: Vec<FileMatch> = Vec::new();
let entries = fs::read_dir(dir)?.collect::<Vec<io::Result<DirEntry>>>();
let gitignore: Option<&DirEntry> = entries
.iter()
.filter_map(|entry| entry.as_ref().ok())
.find(|entry| entry.path().file_name().unwrap() == ".gitignore");
let gitignore = match gitignore {
Some(g) => {
let file = io::BufReader::new(File::open(g.path())?);
file.lines()
.map(|line| line.unwrap().trim().to_owned())
.filter(|line| !line.is_empty() && !line.starts_with('#'))
.collect::<Vec<String>>()
}
None => gitignore_entries.unwrap_or_default(),
};
for entry in entries {
let entry = entry?;
let file_type = entry.file_type()?;
let path = entry.path().to_str().unwrap().to_owned();
if file_type.is_dir() {
if config.use_gitignore {
let should_ignore = gitignore.iter().find(|&line| path.contains(&line.clone()));
if should_ignore.unwrap_or(&String::from("")).len() > 0
|| entry.path().to_str().unwrap().contains("/.git")
{
continue;
}
}
// TODO: Should borrow gitignore instead of cloning..
let mut results =
traverse_dir(&config, &entry.path(), Some(gitignore.clone()), operation)?;
let has_results = results
.iter()
.filter(|mat| !mat.matches.is_empty())
.count()
> 0;
if has_results {
matches.append(&mut results);
}
} else {
if config.use_gitignore {
let should_ignore: Option<&String> = gitignore.iter().find(|&line| path.contains(&line.clone()));
if !should_ignore.unwrap_or(&String::from("")).is_empty()
|| entry.path().to_str().unwrap().contains("/.git")
{
continue;
}
}
let result = operation(&config, &entry.path());
match result {
Result::Ok(result) if !result.matches.is_empty() => matches.push(result),
_ => (),
}
}
}
Ok(matches)
}
fn check_file(config: &Config, path: &Path) -> io::Result<FileMatch> {
let mut pattern = config.pattern.clone();
let file = File::open(&path)?;
let file = io::BufReader::new(file);
let mut matches = Vec::new();
for (number, line) in file.lines().enumerate() {
let mut line = line?;
let orig_line = line.clone();
if config.ignore_case {
line = line.to_lowercase();
pattern = pattern.to_lowercase();
}
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: orig_line.trim().to_string(),
match_indexes: indexes,
});
}
}
Ok(FileMatch {
file_name: path.to_str().unwrap().trim_start_matches("./").to_string(),
matches,
})
}
fn print_report(config: &Config, matches: &[FileMatch]) {
for file in matches {
file.print(config)
}
}