#![allow(unused)]
use std::fmt::{Display, Formatter};
use std::fs::File;
use std::io::{self, BufWriter, StderrLock, StdoutLock, Write};
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
use structopt::StructOpt;
use anyhow::{Context, Result};
use indicatif::{ProgressBar, ProgressState, ProgressStyle};
#[derive(StructOpt, Debug)]
struct Cli {
#[structopt(short = "p", long = "pattern")]
pattern: String,
#[structopt(parse(from_os_str))]
path: std::path::PathBuf,
}
impl Display for Cli {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "({}, {:?})", self.pattern, self.path)
}
}
fn main() -> Result<()> {
let args = Cli::from_args();
println!("Hello, world! {:?}", args);
find_files(&args.path, &args.pattern)?;
Ok(())
}
pub fn find_files(path: &PathBuf, pattern: &str) -> Result<()> {
let f = File::open(&path)
.with_context(|| format!("could not read file `{:?}`", &path))?;
let mut reader = BufReader::new(f);
find_matches(&mut reader, pattern);
Ok(())
}
fn find_matches(reader: &mut BufReader<File>, pattern: &str) {
let pb = indicatif::ProgressBar::new(100);
pb.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})")
.unwrap()
.progress_chars("#>-"));
let stdout = io::stdout().lock(); let stderr = io::stderr().lock();
let mut stdout_handle = io::BufWriter::new(stdout); let mut stderr_handle = io::BufWriter::new(stderr);
let mut idx = 0;
loop {
let mut line = String::new();
let rs = reader.read_line(&mut line);
if rs.is_err() {
break;
}
let len = rs.unwrap();
assert_eq!(line.len(), len);
if len == 0 {
break;
}
find_matche_line(&line, &pattern, &pb, &mut stdout_handle, &mut stderr_handle);
idx += 1;
pb.inc(1);
}
pb.finish_with_message("done");
}
fn find_matche_line(line: &str, pattern: &str, pb: &ProgressBar,
out: &mut impl std::io::Write, err: &mut impl std::io::Write) -> bool{
if line.contains(&pattern) {
writeln!(out, "line is {} bytes long, {}", line.len(), line);
return true;
}
return false;
}
#[cfg(test)]
mod test {
use std::io;
use std::process::Command;
use crate::find_matche_line;
#[test]
fn test_find_matche_line() {
let pb = indicatif::ProgressBar::new(100);
let mut stdout = Vec::new();
let mut stderr = Vec::new();
let line_str = "lorem ipsum\ndolor sit amet";
let rs_1 = find_matche_line(&line_str, "lorem", &pb, &mut stdout, &mut stderr);
assert!(rs_1);
assert_eq!(&line_str.len(), &26usize);
assert_eq!(stdout, b"line is 26 bytes long, lorem ipsum\ndolor sit amet\n");
assert!(stderr.is_empty());
stdout.clear();
stderr.clear();
let rs_2 = find_matche_line("abcd", "lorem", &pb, &mut stdout, &mut stderr);
assert!(!rs_2);
assert!(stdout.is_empty());
assert!(stderr.is_empty());
}
}