1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
extern crate ignore;
extern crate regex;
use std::{cmp, sync::mpsc::{self, Sender}};
use ignore::{WalkBuilder, WalkState};
use regex::{Regex, RegexBuilder};

pub enum Depth {
    None,
    Some(u8),
}

pub enum FileType<'a> {
    None,
    Some(&'a str),
}

pub enum SearchInput<'a> {
    None,
    Some(&'a str),
}

pub fn get_paths (search_location: &str, search_input: SearchInput, file_type: FileType, depth: Depth) -> std::sync::mpsc::Receiver<String>{
    let regex_search_input = build_regex_search_input(search_input, file_type);
    
    let depth = match depth {
        Depth::None => None,
        Depth::Some(depth) => Some(depth as usize),
    };

    let walker = WalkBuilder::new(search_location)
        .hidden(true)
        .git_ignore(true)
        .max_depth(depth)
        .threads(threads())
        .build_parallel();


    let (tx, rx) = mpsc::channel::<String>();

    walker.run(|| {
        let tx: Sender<String> = tx.clone();
        let reg_exp: Regex = regex_search_input.clone();
        let exclude_directories: bool = false;

        Box::new(move |path_entry: Result<ignore::DirEntry, ignore::Error>| {
            if let Ok(entry) = path_entry {
                if exclude_directories && !entry.path().is_file() {
                    WalkState::Continue
                } else {
                    let path: String = entry.path().display().to_string();

                    if is_match(&reg_exp, &path) {
                        match tx.send(path) {
                            Ok(_) => WalkState::Continue,
                            Err(_) => WalkState::Quit,
                        }
                    } else {
                        WalkState::Continue
                    }
                }
            } else {
                WalkState::Continue
            }
        })
    });
    return rx;
}

fn is_match(reg_exp: &Regex, path: &str) -> bool {
    reg_exp.is_match(path)
}

fn build_regex_search_input(search_input: SearchInput, file_type: FileType) -> Regex {
    let file_type = match file_type {
        FileType::None => Some(".*"),
        FileType::Some(file_type) => Some(file_type as &str)
    };
    let search_input = match search_input {
        SearchInput::None => Some(r"\w+\"),
        SearchInput::Some(search_input) => Some(search_input),
    };
    let formatted_search_input = format!(r#"{}{}$"#, search_input.unwrap(), file_type.unwrap()).to_string();
    RegexBuilder::new(&formatted_search_input)
        .build()
        .unwrap()
}

fn threads() -> usize {
    let threads = 0;
    if threads == 0 {
        cmp::min(12, num_cpus::get())
    } else {
        threads
    }
}