summaryrefslogtreecommitdiffstats
path: root/src/path/from.rs
blob: 214c480fa51011954c77575bad5425efade861ff (plain)
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
use {
    super::*,
    directories::UserDirs,
    regex::{self, Captures},
    std::{
        collections::HashMap,
        path::{Path, PathBuf},
    },
};

/// build a usable path from a user input which may be absolute
/// (if it starts with / or ~) or relative to the supplied base_dir.
/// (we might want to try detect windows drives in the future, too)
///
pub fn path_from<P: AsRef<Path>>(base_dir: P, anchor: PathAnchor, input: &str) -> PathBuf {
    let tilde = regex!(r"^~(/|$)");
    if input.starts_with('/') {
        // if the input starts with a `/`, we use it as is
        input.into()
    } else if tilde.is_match(input) {
        // if the input starts with `~` as first token, we replace
        // this `~` with the user home directory
        PathBuf::from(
            &*tilde
                .replace(input, |c: &Captures| {
                    if let Some(user_dirs) = UserDirs::new() {
                        format!("{}{}", user_dirs.home_dir().to_string_lossy(), &c[1],)
                    } else {
                        warn!("no user dirs found, no expansion of ~");
                        c[0].to_string()
                    }
                })
        )
    } else {
        // we put the input behind the source (the selected directory
        // or its parent) and we normalize so that the user can type
        // paths with `../`
        let base_dir = match anchor {
            PathAnchor::Parent => base_dir.as_ref()
                .parent().unwrap_or_else(||base_dir.as_ref())
                .to_path_buf(),
            _ => closest_dir(base_dir.as_ref()),
        };
        normalize_path(base_dir.join(input))
    }
}

pub fn path_str_from<P: AsRef<Path>>(base_dir: P, input: &str) -> String {
    path_from(base_dir, PathAnchor::Unspecified, input).to_string_lossy().to_string()
}

/// replace a group in the execution string, using
///  data from the user input and from the selected line
pub fn do_exec_replacement(ec: &Captures<'_>, replacement_map: &HashMap<String, String>) -> String {
    let name = ec.get(1).unwrap().as_str();
    if let Some(repl) = replacement_map.get(name) {
        if let Some(fmt) = ec.get(2) {
            match fmt.as_str() {
                "path-from-directory" => path_str_from(replacement_map.get("directory").unwrap(), repl),
                "path-from-parent" => path_str_from(replacement_map.get("parent").unwrap(), repl),
                _ => format!("invalid format: {:?}", fmt.as_str()),
            }
        } else {
            repl.to_string()
        }
    } else {
        format!("{{{}}}", name)
    }
}