summaryrefslogtreecommitdiffstats
path: root/src/path/from.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/path/from.rs')
-rw-r--r--src/path/from.rs69
1 files changed, 69 insertions, 0 deletions
diff --git a/src/path/from.rs b/src/path/from.rs
new file mode 100644
index 0000000..214c480
--- /dev/null
+++ b/src/path/from.rs
@@ -0,0 +1,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)
+ }
+}