1
2use std::env;
9use std::error::Error;
10use std::fs;
11
12pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
13 let contents = fs::read_to_string(config.file_path)?;
14 let results = if config.ignore_case {
15 search_case_insensitive(&config.query, &contents)
16 } else {
17 search(&config.query, &contents)
18 };
19 for line in results {
20 println!("{line}");
21 }
22 Ok(())
23}
24
25pub struct Config {
26 pub query: String,
27 pub file_path: String,
28 pub ignore_case: bool,
29}
30
31impl Config {
32 pub fn new(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
33 args.next();
34
35 let query = match args.next() {
36 Some(arg) => arg,
37 None => return Err("dont get a query string"),
38 };
39 let file_path = match args.next() {
40 Some(arg) => arg,
41 None => return Err("dont get a file path"),
42 };
43
44 let ignore_case = env::var("IGNORE_CASE").is_ok();
45
46 Ok(Config {
47 query,
48 file_path,
49 ignore_case,
50 })
51 }
52}
53
54
55
56
57
58pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
69 contents
70 .lines()
71 .filter(|line| line.contains(query))
72 .collect()
73}
74
75pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
76 let query = query.to_lowercase();
77 let mut results = Vec::new();
78
79 for line in contents.lines() {
80 if line.to_lowercase().contains(&query) {
81 results.push(line);
82 }
83 }
84
85 results
86}
87