Repository: casey/just
Pull request #2045 (2024-05-16 20:50:25)

Support prepend()
This PR adds a convenient `prepend` function.
 
`prepend(prefix, base)` takes a `prefix` and a `base` string with space-separated words,
and prepends `prefix` to the beginning of each word in the base string.

For example: `prepend('src', 'foo bar baz')` -> 'src/foo src/bar src/baz'

casey: Seems reasonable to me! How about calling it `prepend`, since that's shorter, and using `split_whitespace` instead of `split(" ")`?
casey: This should also be documented in the readme (along with addsuffix).
gyreas: > This should also be documented in the readme (along with addsuffix).

README? Ah! No wonder I feel something is still missing! Alright, I do that across the PRs. Thanks!

> Seems reasonable to me! How about calling it prepend, since that's shorter, and using split_whitespace instead of split(" ")?

That's a shorter name, okay!
casey: LGTM!

Patch:
diff --git a/README.md b/README.md
index 23ee60d9..7848d652 100644
--- a/README.md
+++ b/README.md
@@ -1397,8 +1397,12 @@ The process ID is: 420
 
 
 #### String Manipulation
+
 - `append(suffix, s)`<sup>master</sup> Append `suffix` to whitespace-separated
-  strings in `s`.
+  strings in `s`. `append('/src', 'foo bar baz')` → `'foo/src bar/src baz/src'`
+- `prepend(prefix, s)`<sup>master</sup> Prepend `prefix` to
+  whitespace-separated strings in `s`. `prepend('src/', 'foo bar baz')` →
+  `'src/foo src/bar src/baz'`
 - `quote(s)` - Replace all single quotes with `'\''` and prepend and append
   single quotes to `s`. This is sufficient to escape special characters for
   many shells, including most Bourne shell descendants.
diff --git a/src/function.rs b/src/function.rs
index 2ed09836..64f607e4 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -24,8 +24,8 @@ pub(crate) fn get(name: &str) -> Option<Function> {
     "arch" => Nullary(arch),
     "blake3" => Unary(blake3),
     "blake3_file" => Unary(blake3_file),
-    "canonicalize" => Unary(canonicalize),
     "cache_directory" => Nullary(|_| dir("cache", dirs::cache_dir)),
+    "canonicalize" => Unary(canonicalize),
     "capitalize" => Unary(capitalize),
     "clean" => Unary(clean),
     "config_directory" => Nullary(|_| dir("config", dirs::config_dir)),
@@ -56,6 +56,7 @@ pub(crate) fn get(name: &str) -> Option<Function> {
     "os_family" => Nullary(os_family),
     "parent_directory" => Unary(parent_directory),
     "path_exists" => Unary(path_exists),
+    "prepend" => Binary(prepend),
     "quote" => Unary(quote),
     "replace" => Ternary(replace),
     "replace_regex" => Ternary(replace_regex),
@@ -265,6 +266,15 @@ fn invocation_directory_native(context: &FunctionContext) -> Result<String, Stri
     })
 }
 
+fn prepend(_context: &FunctionContext, prefix: &str, s: &str) -> Result<String, String> {
+  Ok(
+    s.split_whitespace()
+      .map(|s| format!("{prefix}{s}"))
+      .collect::<Vec<String>>()
+      .join(" "),
+  )
+}
+
 fn join(
   _context: &FunctionContext,
   base: &str,


Test patch:
diff --git a/tests/functions.rs b/tests/functions.rs
index 3cc1d40e..a9fb98b6 100644
--- a/tests/functions.rs
+++ b/tests/functions.rs
@@ -501,6 +501,28 @@ fn append() {
   );
 }
 
+#[test]
+fn prepend() {
+  assert_eval_eq("prepend('8', 'r s t\n  \n  ')", "8r 8s 8t");
+  assert_eval_eq(
+    "prepend('src/', 'main sar x11')",
+    "src/main src/sar src/x11",
+  );
+  assert_eval_eq("prepend('-', 'c\tv h\ny')", "-c -v -h -y");
+  assert_eval_eq(
+    "prepend('0000', '11 10 01 00')",
+    "000011 000010 000001 000000",
+  );
+  assert_eval_eq(
+    "prepend('April-', '
+      1st,
+        17th,
+    20th,
+    ')",
+    "April-1st, April-17th, April-20th,",
+  );
+}
+
 #[test]
 #[cfg(not(windows))]
 fn join() {