diff --git a/Cargo.lock b/Cargo.lock
index 501366d..7fd0767 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -17,6 +17,15 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "anstream"
version = "0.6.21"
@@ -297,6 +306,7 @@ dependencies = [
"color-eyre",
"facet",
"mlua",
+ "regex",
"thiserror",
"tracing",
"tracing-subscriber",
@@ -549,6 +559,35 @@ dependencies = [
"bitflags",
]
+[[package]]
+name = "regex"
+version = "1.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
+
[[package]]
name = "rustc-demangle"
version = "0.1.26"
diff --git a/Cargo.toml b/Cargo.toml
index 43c7ced..6ef52d3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,6 +8,7 @@ color-eyre = "*"
clap = { version = "*", features = ["derive"] }
facet = "*"
mlua = { version = "*", features = ["lua54", "vendored"] }
+regex = "*"
thiserror = "*"
tracing = "*"
tracing-subscriber = "*"
diff --git a/src/main.rs b/src/main.rs
index 7b58005..9ea5be0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,12 +4,14 @@ use color_eyre::{
eyre::{WrapErr, eyre},
};
use mlua::prelude::*;
+use regex::Regex;
use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::Path;
use std::rc::Rc;
+use std::sync::LazyLock;
use thiserror::Error;
use tracing::{debug, info};
@@ -60,16 +62,28 @@ impl From<LuaError> for FrorkError {
}
}
-fn expand_tilde(path: &str) -> String {
- if path.starts_with('~') {
+static ENV_VAR_REGEX: LazyLock<Regex> =
+ LazyLock::new(|| Regex::new(r"\$([A-Za-z_][A-Za-z0-9_]*)").unwrap());
+
+fn expand_path(path: &str) -> String {
+ let mut expanded = path.to_string();
+
+ // Expand tilde
+ if expanded.starts_with('~') {
if let Ok(home) = env::var("HOME") {
- path.replacen('~', &home, 1)
- } else {
- path.to_string()
+ expanded = expanded.replacen('~', &home, 1);
}
- } else {
- path.to_string()
}
+
+ // Expand environment variables using regex
+ expanded = ENV_VAR_REGEX
+ .replace_all(&expanded, |caps: ®ex::Captures| {
+ let var_name = caps.get(1).unwrap().as_str();
+ env::var(var_name).unwrap_or_else(|_| caps.get(0).unwrap().as_str().to_string())
+ })
+ .to_string();
+
+ expanded
}
#[derive(Debug)]
@@ -149,7 +163,7 @@ impl Symlink {
let strings: Vec<String> = args_vec
.into_iter()
.map(|val| {
- val.to_string().map(|s| expand_tilde(&s)).map_err(|_| {
+ val.to_string().map(|s| expand_path(&s)).map_err(|_| {
FrorkError::InvalidArguments("Arguments must be strings".to_string())
})
})
@@ -225,7 +239,7 @@ impl Directory {
.to_string()
.map_err(|_| FrorkError::InvalidArguments("Argument must be a string".to_string()))?;
- let expanded_path = expand_tilde(&path);
+ let expanded_path = expand_path(&path);
Ok(Self {
path: expanded_path,