shell/
glob.rs

1use std::path::PathBuf;
2
3pub enum GlobOutput {
4    Arg(PathBuf),
5    Args(Vec<PathBuf>),
6}
7
8pub fn expand_glob(pat: impl Into<PathBuf>) -> GlobOutput {
9    let pat: PathBuf = pat.into();
10    let mut files = Vec::new();
11    if let Ok(paths) = glob::glob(&pat.to_string_lossy()) {
12        for p in paths {
13            match p {
14                Ok(p) => {
15                    files.push(p);
16                }
17                Err(err) => {
18                    eprintln!("glob error while iterating {}, {}", pat.display(), err);
19                }
20            }
21        }
22        if files.is_empty() {
23            // Got nothing so fall back on pattern.
24            if pat.to_str().unwrap_or("").contains('\\') {
25                GlobOutput::Arg(remove_escapes(pat.to_str().unwrap_or("")).into())
26            } else {
27                GlobOutput::Arg(pat)
28            }
29        } else if pat.starts_with("./") {
30            GlobOutput::Args(
31                files
32                    .iter()
33                    .cloned()
34                    .map(|f| {
35                        let mut nf = PathBuf::new();
36                        nf.push("./");
37                        nf.push(f);
38                        nf
39                    })
40                    .collect(),
41            )
42        } else {
43            GlobOutput::Args(files)
44        }
45    } else if pat.to_str().unwrap_or("").contains('\\') {
46        GlobOutput::Arg(remove_escapes(pat.to_str().unwrap_or("")).into())
47    } else {
48        GlobOutput::Arg(pat)
49    }
50}
51
52fn remove_escapes(pat: &str) -> String {
53    let mut ret = String::new();
54    let mut last_esc = false;
55    for ch in pat.chars() {
56        match ch {
57            '\\' if last_esc => {
58                ret.push('\\');
59                last_esc = false;
60            }
61            '\\' => last_esc = true,
62            '*' if last_esc => {
63                ret.push('*');
64                last_esc = false;
65            }
66            '?' if last_esc => {
67                ret.push('?');
68                last_esc = false;
69            }
70            '[' if last_esc => {
71                ret.push('[');
72                last_esc = false;
73            }
74            ']' if last_esc => {
75                ret.push(']');
76                last_esc = false;
77            }
78            _ => {
79                if last_esc {
80                    ret.push('\\');
81                }
82                ret.push(ch);
83                last_esc = false;
84            }
85        }
86    }
87    ret
88}