string_parser/
lib.rs

1//! # string_parser
2//! 
3//! string_parser is a crate that find tokens in source files and parse the inside<br/> 
4
5use std::fs::File;
6use std::io;
7use std::io::prelude::*;
8use std::io::BufReader;
9
10#[cfg(test)]
11mod tests {
12    use super::*;
13    #[test]
14    fn doc_test() {
15        let mut s1 = String::new();
16
17        let callback = |s : String| { 
18            if s != String::from("foo"){
19                panic!();
20            }
21            s1 = s;
22        };
23
24
25        assert_eq!(string_parser("./text", "'", end_filter, callback).unwrap(), ());
26
27        fn end_filter(c : Vec<char>) -> bool{
28            for char in &c {
29                print!("{}", char);
30            }
31            print!("\n");
32            if c.last().unwrap() == &'\'' {
33                println!("end filter");
34                return true;
35            }
36            else {
37                return false;
38            }
39        }
40    }
41
42    
43
44    
45}
46
47/// Main function of the create
48/// # Arguments
49/// * `path` - the path to the file to search from
50/// * `text` - the text to search
51/// * `end_filter` - the function called at each character to check if we're still within the token. Sould return true when out of the token.
52/// * `callback` - the function called when the text is exited. take the inside of the token as argument
53/// # Examples
54/// ./text being "...'foo'..."
55/// ```no_run
56/// extern crate string_parser;
57/// use string_parser::string_parser; 
58/// 
59/// fn end_filter(c : Vec<char>) -> bool{            
60///     if c.last().unwrap()== &'\'' {
61///         return true;
62///         }
63///     else {
64///         return false;
65///         }   
66/// }
67/// //can also use closures
68/// let callback = |s : String| {
69///     assert_eq!(String::from("foo"), s); 
70/// };
71/// 
72/// string_parser("./text", "'", end_filter, callback).unwrap();
73pub fn string_parser(path : &str,text : &str, end_filter : impl Fn(Vec<char>) -> bool ,mut callback : impl FnMut(String)) -> Result<(), io::Error> {
74    //open the file and put it as a string into file_buf
75    let mut inside : bool = false; // true if the cursor is inside the statement
76    let mut first : bool = true; // true is it's the first iteration
77    let mut string_buffer = String::new();
78
79    let mut file_buf = String::new(); //the whole file as a String
80    let f = File::open(path)?;
81    let mut f = BufReader::new(f);
82    f.read_to_string(&mut file_buf)?;
83
84    let mut buff : Vec<char> = vec![' '; text.len()];
85    //loop through every character of the file
86    for c in file_buf.chars() {
87        let mut i : usize = 0;
88        while i < buff.len() -1 {
89            buff[i] = buff[i+1];
90            i += 1;
91        }
92        buff[i] = c;
93        i = 0;
94
95        if inside && !end_filter(buff.clone()){
96            string_buffer.push(c);
97        }
98        else if inside && !first {
99            inside = false;
100            // let s = string_buffer.pop();
101            callback(string_buffer.clone());
102            string_buffer.clear();
103        }
104        else {
105            while i < buff.len(){
106                // println!("buff[{}] : {}, text[{}] : {}", i, buff[i], i, text.chars().nth(i).unwrap());
107                if buff[i] != text.chars().nth(i).unwrap() {
108                    break;
109                }
110                i += 1;
111            }
112            if i == text.len() {
113                inside = true;
114                first = false;
115            }
116        }
117        
118    }
119    Ok(())
120}
121///Like [string_parser](./fn.string_parser.html) but the callback function also take the line number as arguments
122pub fn string_parser_with_line(path : &str,text : &str, end_filter : impl Fn(Vec<char>) -> bool ,mut callback : impl FnMut(String, usize)) -> Result<(), io::Error> {
123    //open the file and put it as a string into file_buf
124    let mut inside : bool = false; // true if the cursor is inside the statement
125    let mut first : bool = true; // true is it's the first iteration
126    let mut string_buffer = String::new();
127
128    let mut file_buf = String::new(); //the whole file as a String
129
130    let mut line : usize = 0;
131    let f = File::open(path)?;
132    let mut f = BufReader::new(f);
133    f.read_to_string(&mut file_buf)?;
134
135    let mut buff : Vec<char> = vec![' '; text.len()];
136    //loop through every character of the file
137    for c in file_buf.chars() {
138        if c == '\n' {
139            line += 1;
140        }
141        let mut i : usize = 0;
142        while i < buff.len() -1 {
143            buff[i] = buff[i+1];
144            i += 1;
145        }
146        buff[i] = c;
147        i = 0;
148
149        if inside && !end_filter(buff.clone()){
150            string_buffer.push(c);
151        }
152        else if inside && !first {
153            inside = false;
154            // let s = string_buffer.pop();
155            callback(string_buffer.clone(), line);
156            string_buffer.clear();
157        }
158        else {
159            while i < buff.len(){
160                // println!("buff[{}] : {}, text[{}] : {}", i, buff[i], i, text.chars().nth(i).unwrap());
161                if buff[i] != text.chars().nth(i).unwrap() {
162                    break;
163                }
164                i += 1;
165            }
166            if i == text.len() {
167                inside = true;
168                first = false;
169            }
170        }
171        
172    }
173
174    if inside {
175        callback(string_buffer.clone(), line +1 );
176    }
177    Ok(())
178}
179
180///Like [string_parser_with_line](./fn.string_parser_with_line.html) but the callback function also take the file path as arguments
181pub fn string_parser_with_file(path : &str,text : &str, end_filter : impl Fn(Vec<char>) -> bool ,mut callback : impl FnMut(String, usize, &str)) -> Result<(), io::Error> {
182    //open the file and put it as a string into file_buf
183    let mut inside : bool = false; // true if the cursor is inside the statement
184    let mut first : bool = true; // true is it's the first iteration
185    let mut string_buffer = String::new();
186
187    let mut file_buf = String::new(); //the whole file as a String
188
189    let mut line : usize = 0;
190    let f = File::open(path)?;
191    let mut f = BufReader::new(f);
192    f.read_to_string(&mut file_buf)?;
193
194    let mut buff : Vec<char> = vec![' '; text.len()];
195    //loop through every character of the file
196    for c in file_buf.chars() {
197        if c == '\n' {
198            line += 1;
199        }
200        let mut i : usize = 0;
201        while i < buff.len() -1 {
202            buff[i] = buff[i+1];
203            i += 1;
204        }
205        buff[i] = c;
206        i = 0;
207
208        if inside && !end_filter(buff.clone()){
209            string_buffer.push(c);
210        }
211        else if inside && !first {
212            inside = false;
213            // let s = string_buffer.pop();
214            callback(string_buffer.clone(), line, path);
215            string_buffer.clear();
216        }
217        else {
218            while i < buff.len(){
219                // println!("buff[{}] : {}, text[{}] : {}", i, buff[i], i, text.chars().nth(i).unwrap());
220                if buff[i] != text.chars().nth(i).unwrap() {
221                    break;
222                }
223                i += 1;
224            }
225            if i == text.len() {
226                inside = true;
227                first = false;
228            }
229        }
230        
231    }
232
233    if inside {
234        callback(string_buffer.clone(), line +1, path);
235    }
236    Ok(())
237}