1use std::fs;
7use std::error::Error;
8use std::env;
9
10pub struct Config {
11 pub query: String,
12 pub file_path: String,
13 pub ignore_case: bool,
14}
15
16impl Config {
17 pub fn build(mut args: impl Iterator<Item=String>) -> Result<Config, &'static str> {
18 args.next();
19
20 let query = match args.next() {
21 Some(val) => val,
22 None => panic!("dd")
23 };
24 let file_path = match args.next() {
25 Some(val) => val,
26 None => panic!("yy")
27 };
28
29 let ignore_case = env::var("IGNORE_CASE").is_ok();
30
31 Ok(Config {query, file_path, ignore_case})
32 }
33}
34
35pub fn run(cfg : &Config) -> Result<(), Box<dyn Error>>{
36
37 let contents = fs::read_to_string(cfg.file_path.clone())?;
38
39 let results: Vec<&str> = if cfg.ignore_case {
40 search_case_insensitive(&cfg.query, &contents)
41 } else {
42 search(&cfg.query, &contents)
43 };
44
45 if results.len() > 0 {
46 for line in results {
47 println!("{line}");
48 }
49 }
50
51 Ok(())
52}
53
54pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str>{
55 contents
56 .lines()
57 .filter(|line|line.contains(query))
58 .collect()
59
60}
61
62pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str>{
79 contents
80 .lines()
81 .filter(|line| line.to_lowercase().contains(&query.to_lowercase()))
82 .collect()
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 #[ignore = "reason"]
91 fn case_sensitive(){
92 let query = "Duct";
93 let contents = "\
94 Rust:
95safe, fast, productive
96 Pick three.";
97
98 let vec: Vec<&str> = search(query, contents);
99 println!("{:?}", vec);
100 assert_eq!(vec!["safe, fast, productive"], vec);
101
102 }
103
104 #[test]
105 fn case_insensitive() {
106 let query = "rUsT";
107 let contents = "\
108Rust:
109safe, fast, productive
110Pick three.
111Trust me.";
112
113 let vec: Vec<&str> = search_case_insensitive(query, contents);
114 println!("{:?}", vec);
115 assert_eq!(
116 vec!["Rust:", "Trust me."],
117 vec);
118
119 }
120}