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