Repository: casey/just
Pull request #999 (2021-10-14 07:28:35)

Add `trim_end(s)` and `trim_start(s)` functions


Patch:
diff --git a/README.adoc b/README.adoc
index 48234d21..92899d54 100644
--- a/README.adoc
+++ b/README.adoc
@@ -857,8 +857,10 @@ The executable is at: /bin/just
 - `lowercase(s)` - Convert `s` to lowercase.
 - `replace(s, from, to)` - Replace all occurrences of `from` in `s` to `to`.
 - `trim(s)` - Remove leading and trailing whitespace from `s`.
+- `trim_end(s)` - Remove trailing whitespace from `s`.
 - `trim_end_match(s, pat)` - Remove suffix of `s` matching `pat`.
 - `trim_end_matches(s, pat)` - Repeatedly remove suffixes of `s` matching `pat`.
+- `trim_start(s)` - Remove leading whitespace from `s`.
 - `trim_start_match(s, pat)` - Remove prefix of `s` matching `pat`.
 - `trim_start_matches(s, pat)` - Repeatedly remove prefixes of `s` matching `pat`.
 - `uppercase(s)` - Convert `s` to uppercase.
diff --git a/src/function.rs b/src/function.rs
index 178fcc44..2e88eb51 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -28,8 +28,10 @@ lazy_static! {
     ("parent_directory", Unary(parent_directory)),
     ("replace", Ternary(replace)),
     ("trim", Unary(trim)),
+    ("trim_end", Unary(trim_end)),
     ("trim_end_match", Binary(trim_end_match)),
     ("trim_end_matches", Binary(trim_end_matches)),
+    ("trim_start", Unary(trim_start)),
     ("trim_start_match", Binary(trim_start_match)),
     ("trim_start_matches", Binary(trim_start_matches)),
     ("uppercase", Unary(uppercase)),
@@ -201,6 +203,10 @@ fn trim(_context: &FunctionContext, s: &str) -> Result<String, String> {
   Ok(s.trim().to_owned())
 }
 
+fn trim_end(_context: &FunctionContext, s: &str) -> Result<String, String> {
+  Ok(s.trim_end().to_owned())
+}
+
 fn trim_end_match(_context: &FunctionContext, s: &str, pat: &str) -> Result<String, String> {
   Ok(s.strip_suffix(pat).unwrap_or(s).to_owned())
 }
@@ -209,6 +215,10 @@ fn trim_end_matches(_context: &FunctionContext, s: &str, pat: &str) -> Result<St
   Ok(s.trim_end_matches(pat).to_owned())
 }
 
+fn trim_start(_context: &FunctionContext, s: &str) -> Result<String, String> {
+  Ok(s.trim_start().to_owned())
+}
+
 fn trim_start_match(_context: &FunctionContext, s: &str, pat: &str) -> Result<String, String> {
   Ok(s.strip_prefix(pat).unwrap_or(s).to_owned())
 }


Test patch:
diff --git a/tests/functions.rs b/tests/functions.rs
index ee5a77f8..8e7aff28 100644
--- a/tests/functions.rs
+++ b/tests/functions.rs
@@ -308,6 +308,7 @@ fn assert_eval_eq(expression: &str, result: &str) {
     .justfile(format!("x := {}", expression))
     .args(&["--evaluate", "x"])
     .stdout(result)
+    .unindent_stdout(false)
     .run();
 }
 
@@ -336,3 +337,13 @@ fn trim_start_match() {
   assert_eval_eq("trim_start_match('oof', 'o')", "of");
   assert_eval_eq("trim_start_match('ababf', 'ab')", "abf");
 }
+
+#[test]
+fn trim_start() {
+  assert_eval_eq("trim_start('  f  ')", "f  ");
+}
+
+#[test]
+fn trim_end() {
+  assert_eval_eq("trim_end('  f  ')", "  f");
+}
diff --git a/tests/test.rs b/tests/test.rs
index 31cee0d2..8f8d31e0 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -47,6 +47,7 @@ pub(crate) struct Test {
   pub(crate) stdout: String,
   pub(crate) suppress_dotenv_load_warning: bool,
   pub(crate) tempdir: TempDir,
+  pub(crate) unindent_stdout: bool,
 }
 
 impl Test {
@@ -68,6 +69,7 @@ impl Test {
       stdout: String::new(),
       suppress_dotenv_load_warning: true,
       tempdir,
+      unindent_stdout: true,
     }
   }
 
@@ -147,6 +149,11 @@ impl Test {
     tree.instantiate(&self.tempdir.path()).unwrap();
     self
   }
+
+  pub(crate) fn unindent_stdout(mut self, unindent_stdout: bool) -> Self {
+    self.unindent_stdout = unindent_stdout;
+    self
+  }
 }
 
 impl Test {
@@ -156,7 +163,11 @@ impl Test {
       fs::write(self.justfile_path(), justfile).unwrap();
     }
 
-    let stdout = unindent(&self.stdout);
+    let stdout = if self.unindent_stdout {
+      unindent(&self.stdout)
+    } else {
+      self.stdout
+    };
     let stderr = unindent(&self.stderr);
 
     let mut dotenv_path = self.tempdir.path().to_path_buf();