sempgrep/
lib.rs

1use std::error::Error;
2use std::fs;
3use std::env;
4
5pub struct Config {
6    pub query: String,
7    pub file_path: String,
8    pub ignore_case: bool,
9}
10
11impl Config {
12    pub fn build(
13        mut args: impl Iterator<Item = String>,
14    ) -> Result<Config, &'static str> {
15        args.next();
16
17        let query = match args.next() {
18            Some(arg) => arg,
19            None => return Err("Didnt get a query string"),
20        };
21        let file_path = match args.next() {
22            Some(arg) => arg,
23            None => return Err("Didnt get a file path"),
24        };
25        
26        let ignore_case = env::var("IGNORE_CASE").is_ok();
27
28        Ok(Config {
29            query, 
30            file_path,
31            ignore_case,
32        })
33    }
34}
35
36pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
37    let contents = fs::read_to_string(config.file_path)?;
38
39    let results = if config.ignore_case {
40        search_case_insensitive(&config.query, &contents)
41    } else {
42        search(&config.query, &contents)
43    };
44    for line in results {
45        println!("{}", line);
46    }
47
48    Ok(())
49}
50
51pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
52    contents
53        .lines()
54        .filter(|line| line.contains(query))
55        .collect()
56}
57
58pub fn search_case_insensitive<'a>(
59    query: &str, 
60    contents: &'a str,
61) -> Vec<&'a str> {
62    let query = query.to_lowercase();
63
64    contents
65        .lines()
66        .filter(|line| line.to_lowercase().contains(&query))
67        .collect()
68}
69
70
71// test cases
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn case_sensitive() {
79        let query = "duct";
80        let contents =  "\
81Rust:
82safe, fast, productive.
83Pick three.
84Duct tape.";
85        
86        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
87    }
88
89    #[test]
90    fn case_insensitive() {
91        let query = "rUsT";
92        let contents = "\
93Rust:
94safe, fast, productive.
95Pick three.
96Trust me.";
97
98        assert_eq!(
99            vec!["Rust:", "Trust me."],
100            search_case_insensitive(query, contents)
101        )
102    }
103}