Skip to main content

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}