1 use {
2 super::*,
3 directories::UserDirs,
4 ahash::AHashMap,
5 lazy_regex::*,
6 std::path::{Path, PathBuf},
7 };
8
9 /// Build a usable path from a user input which may be absolute
10 /// (if it starts with / or ~) or relative to the supplied base_dir.
11 /// (we might want to try detect windows drives in the future, too)
path_from<P: AsRef<Path>>( base_dir: P, anchor: PathAnchor, input: &str, ) -> PathBuf12 pub fn path_from<P: AsRef<Path>>(
13 base_dir: P,
14 anchor: PathAnchor,
15 input: &str,
16 ) -> PathBuf {
17 let tilde = regex!(r"^~(/|$)");
18 if input.starts_with('/') {
19 // if the input starts with a `/`, we use it as is
20 input.into()
21 } else if tilde.is_match(input) {
22 // if the input starts with `~` as first token, we replace
23 // this `~` with the user home directory
24 PathBuf::from(
25 &*tilde
26 .replace(input, |c: &Captures| {
27 if let Some(user_dirs) = UserDirs::new() {
28 format!(
29 "{}{}",
30 user_dirs.home_dir().to_string_lossy(),
31 &c[1],
32 )
33 } else {
34 warn!("no user dirs found, no expansion of ~");
35 c[0].to_string()
36 }
37 })
38 )
39 } else {
40 // we put the input behind the source (the selected directory
41 // or its parent) and we normalize so that the user can type
42 // paths with `../`
43 let base_dir = match anchor {
44 PathAnchor::Parent => base_dir
45 .as_ref()
46 .parent()
47 .unwrap_or_else(|| base_dir.as_ref())
48 .to_path_buf(),
49 _ => closest_dir(base_dir.as_ref()),
50 };
51 normalize_path(base_dir.join(input))
52 }
53 }
54
path_str_from<P: AsRef<Path>>(base_dir: P, input: &str) -> String55 pub fn path_str_from<P: AsRef<Path>>(base_dir: P, input: &str) -> String {
56 path_from(base_dir, PathAnchor::Unspecified, input)
57 .to_string_lossy()
58 .to_string()
59 }
60
61 /// Replace a group in the execution string, using
62 /// data from the user input and from the selected line
do_exec_replacement( ec: &Captures<'_>, replacement_map: &AHashMap<String, String>, ) -> String63 pub fn do_exec_replacement(
64 ec: &Captures<'_>,
65 replacement_map: &AHashMap<String, String>,
66 ) -> String {
67 let name = ec.get(1).unwrap().as_str();
68 if let Some(repl) = replacement_map.get(name) {
69 if let Some(fmt) = ec.get(2) {
70 match fmt.as_str() {
71 "path-from-directory" => path_str_from(replacement_map.get("directory").unwrap(), repl),
72 "path-from-parent" => path_str_from(replacement_map.get("parent").unwrap(), repl),
73 _ => format!("invalid format: {:?}", fmt.as_str()),
74 }
75 } else {
76 repl.to_string()
77 }
78 } else {
79 format!("{{{}}}", name)
80 }
81 }
82