1use std::error::Error;
13use std::fs;
14use std::env;
15use std::env::Args;
16use std::process;
17use clap::{Parser,ColorChoice};
18
19
20
21#[derive(Parser, Debug)]
22#[command(
23name = "minigrep_jimloop-tool",
24version = "1.0",
25about = "minigrep_jimloop-tool 🎯,基于rust编写",
26long_about = None,
27override_usage = "minigrep_jimloop [EXE] -i <IGNORE_CASE> -s <STRING> -f <FILE>",
28color = ColorChoice::Always,
29)]
30pub struct Config{
31 #[arg(short = 's',long)]
32 pub query:String,
33 #[arg(short = 'f', long, help = r#"指定搜索文件的路径"#)]
34 pub file_path:String,
35 #[arg(short = 'i',long,default_value_t=false)]
36 pub ignore_case:bool,
37}
38
39impl Config{
40 pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config,&'static str>{
41 args.next();
42 let query:String = match args.next(){
43 None => return Err("Didn't get a query string."),
44 Some(arg) => arg,
45 };
46 let file_path:String = match args.next(){
47 None => return Err("Didn't get a file path."),
48 Some(arg) => arg,
49 };
50 let mut ignore_case:bool = false;
51 match args.next(){
52 Some(arg) => if arg=="true" || arg=="1" {ignore_case = true},
53 _ => { ignore_case = false},
54 };
55 if !ignore_case{
56 ignore_case = env::var("IGNORE_CASE").is_ok();
57 }
58 Ok(Config{ query, file_path,ignore_case})
59 }
60}
61
62pub fn run()-> Result<(),Box<dyn Error>>{
63 let config = Config::parse();
64 let contents:String = fs::read_to_string(config.file_path)?;
65 let results = if config.ignore_case{
66 search_case_insensitive(&config.query,&contents)
67 }else {
68 search(&config.query,&contents)
69 };
70 for line in results{
71 println!("{}",line);
72 }
73 Ok(())
74}
75
76
77pub fn run_with_args()-> Result<(),Box<dyn Error>>{
78 let args:Args = env::args();
79 let config = Config::build(args).unwrap_or_else(|err|{
80 eprintln!("Problem parsing arguments: {err}");
81 process::exit(1);
82 });
83 let contents:String = fs::read_to_string(&config.file_path)?;
84 let results = if config.ignore_case{
85 search_case_insensitive(&config.query,&contents)
86 }else {
87 search(&config.query,&contents)
88 };
89 for line in results{
90 println!("{}",line);
91 }
92 Ok(())
93}
94
95pub fn search<'a>(query:&str,contents:&'a str) -> Vec<&'a str>{
97 contents
98 .lines()
99 .filter(|line| { line.contains(query) })
100 .collect()
101}
102
103
104pub fn search_case_insensitive<'a>(query:&str,contents:&'a str) -> Vec<&'a str>{
120 contents
121 .lines()
122 .filter(|line| line.to_lowercase().contains(&query.to_lowercase()))
123 .collect()
124}