1use std::{env, error::Error, fs};
2
3pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
4 let content = fs::read_to_string(&config.filename)?; let search_result = if config.case_sensitive {
7 search(&config.query, &content)
8 } else {
9 search_case_insensitive(&config.query, &content)
10 };
11 for line in search_result {
12 println!("find: {}", line);
13 }
14 Ok(()) }
17
18pub struct Config {
19 pub cmd: String,
20 pub query: String,
21 pub filename: String,
22 pub case_sensitive: bool,
23}
24
25impl Config {
26 pub fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
27 if args.len() < 3 {
28 return Err("Parsing args failed, args were insuffient");
30 }
31 Ok(Config {
33 cmd: match args.next() {
34 Some(arg) => arg,
35 None => return Err("没有cmd "),
36 },
37 query: match args.next() {
38 Some(arg) => arg,
39 None => return Err("没有query字符串 "),
40 },
41 filename: match args.next() {
42 Some(arg) => arg,
43 None => return Err("没有filename字符串 "),
44 },
45 case_sensitive: env::var("CASE_INSENSITIVE").is_err(), })
50 }
51}
52
53fn search<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
54 content
66 .lines() .filter(|line| line.contains(query)) .collect() }
70
71fn search_case_insensitive<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
72 let lowercase_query = query.to_ascii_lowercase();
81 content
82 .lines()
83 .filter(|line| line.to_lowercase().contains(&lowercase_query))
84 .collect()
85}
86
87#[cfg(test)]
88mod tests {
89 use std::vec;
90
91 use super::*;
92
93 #[test]
95 fn case_sensitive() {
96 let query = "duct";
97 let contents = "\
98Rust:
99safe, fast, productive.
100Pick three.
101Duct tape.";
102 assert_eq!(vec!["safe, fast, productive."], search(query, contents))
103 }
104
105 #[test]
106 fn case_insensitive() {
107 let query = "rUsT";
108 let contents = "\
109Rust:
110safe, fast, productive.
111Pick three.
112rust me";
113 assert_eq!(
114 vec!["Rust:", "rust me"],
115 search_case_insensitive(query, contents)
116 )
117 }
118}