ifun_grep/lib.rs
1//! ifun_grep is a string search library
2//!
3//! Supports case sensitive search.
4//!
5
6use ansi_term::Colour::{Red, Yellow};
7use anyhow::{Context, Result};
8use clap::Parser;
9use log;
10use std::fs;
11use thiserror::Error;
12
13#[derive(Error, Debug)]
14pub enum IfunError {
15 #[error("the file is't exist")]
16 FileNotExist(#[from] std::io::Error),
17}
18
19/// the struct `Config` defines command line params.
20///
21/// # Example
22///
23/// ```
24/// let search = String::from("let");
25/// let config = ifun_grep::Config {
26/// search,
27/// file_path:String::from("hello.txt"),
28/// ignore_case:false,
29/// };
30///
31/// ```
32///
33#[derive(Parser)]
34#[command(name = "ifun-grep")]
35#[command(author = "hboot <bobolity@163.com>")]
36#[command(version = "0.2.0")]
37#[command(about="A simple fake grep",long_about=None)]
38pub struct Config {
39 #[arg(short, long)]
40 pub search: String,
41 #[arg(short, long)]
42 pub file_path: String,
43 #[arg(short, long)]
44 pub ignore_case: bool,
45}
46
47/// the fun is used to execute search
48///
49/// # example
50/// ```
51/// let search = String::from("let");
52/// let config = ifun_grep::Config {
53/// search,
54/// file_path:String::from("hello.txt"),
55/// ignore_case:false,
56/// };
57///
58/// let result = ifun_grep::run(config);
59///
60/// assert!(result.is_ok());
61/// ```
62///
63pub fn run(config: Config) -> Result<(), anyhow::Error> {
64 let file_path = config.file_path.clone();
65 let content = fs::read_to_string(config.file_path)
66 .with_context(|| format!("could not read file {}", file_path))?;
67
68 let result;
69 if config.ignore_case {
70 result = find_insensitive(&config.search, &content);
71 } else {
72 result = find(&config.search, &content);
73 }
74 for line in result {
75 log::info!("{}", Red.on(Yellow).blink().paint(line));
76 }
77
78 Ok(())
79}
80
81/// the fun is used to execute search. it's case sensitive
82///
83/// # example
84///
85/// ```
86/// let search = "rust";
87/// let content = "\
88/// nice. rust
89/// I'm hboot.
90/// hello world.
91/// Rust
92/// ";
93
94/// assert_eq!(vec!["nice. rust"], ifun_grep::find(search, content));
95/// ```
96///
97pub fn find<'a>(search: &str, content: &'a str) -> Vec<&'a str> {
98 let mut result = vec![];
99 for line in content.lines() {
100 if line.contains(search) {
101 // 符合,包含了指定字符串
102 result.push(line);
103 }
104 }
105
106 result
107}
108/// the fun is used to execute search. it's case sensitive
109///
110/// # example
111///
112/// ```
113/// let search = "rust";
114/// let content = "\
115/// nice. rust
116/// I'm hboot.
117/// hello world.
118/// Rust
119/// ";
120/// assert_eq!(vec!["nice. rust","Rust"], ifun_grep::find_insensitive(search, content));
121/// ```
122///
123pub fn find_insensitive<'a>(search: &str, content: &'a str) -> Vec<&'a str> {
124 let mut result = vec![];
125 // 搜索 字符串转小写
126 let search = search.to_lowercase();
127
128 for line in content.lines() {
129 // 文本行内容转小写
130 if line.to_lowercase().contains(&search) {
131 // 符合,包含了指定字符串
132 result.push(line);
133 }
134 }
135
136 result
137}