From be11a2622644897e35cc3956626faf8f757741af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Giancarlo=20Fran=C3=A7a?=
<15658199+gVirtu@users.noreply.github.com>
Date: Thu, 27 Oct 2022 00:44:18 -0300
Subject: [PATCH] Add more case-conversion functions (#1383)
---
Cargo.lock | 1 +
Cargo.toml | 1 +
README.md | 14 ++++++++
extras/just.sublime-syntax | 2 +-
src/function.rs | 40 ++++++++++++++++++++++
tests/functions.rs | 70 ++++++++++++++++++++++++++++++++++++++
6 files changed, 127 insertions(+), 1 deletion(-)
diff --git a/Cargo.lock b/Cargo.lock
index 9358f3e..8b1b515 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -316,6 +316,7 @@ dependencies = [
"edit-distance",
"env_logger",
"executable-path",
+ "heck 0.4.0",
"lazy_static",
"lexiclean",
"libc",
diff --git a/Cargo.toml b/Cargo.toml
index 01f9ce0..a0a06fe 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,6 +26,7 @@ derivative = "2.0.0"
dotenv = "0.15.0"
edit-distance = "2.0.0"
env_logger = "0.9.0"
+heck = "0.4.0"
lazy_static = "1.0.0"
lexiclean = "0.0.1"
libc = "0.2.0"
diff --git a/README.md b/README.md
index 67823d6..2ef98bc 100644
--- a/README.md
+++ b/README.md
@@ -1145,12 +1145,24 @@ The executable is at: /bin/just
- `capitalize(s)`master - Convert first character of `s` to uppercase and the rest to lowercase.
+- `kebabcase(s)`master - Convert `s` to `kebab-case`.
+
+- `lowercamelcase(s)`master - Convert `s` to `lowerCamelCase`.
+
- `lowercase(s)` - Convert `s` to lowercase.
- `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.
- `replace(s, from, to)` - Replace all occurrences of `from` in `s` to `to`.
+- `shoutykebabcase(s)`master - Convert `s` to `SHOUTY-KEBAB-CASE`.
+
+- `shoutysnakecase(s)`master - Convert `s` to `SHOUTY_SNAKE_CASE`.
+
+- `snakecase(s)`master - Convert `s` to `snake_case`.
+
+- `titlecase(s)`master - Convert `s` to `Title Case`.
+
- `trim(s)` - Remove leading and trailing whitespace from `s`.
- `trim_end(s)` - Remove trailing whitespace from `s`.
@@ -1167,6 +1179,8 @@ The executable is at: /bin/just
- `uppercase(s)` - Convert `s` to uppercase.
+- `uppercamelcase(s)`master - Convert `s` to `UpperCamelCase`.
+
#### Path Manipulation
##### Fallible
diff --git a/extras/just.sublime-syntax b/extras/just.sublime-syntax
index b5525a6..fc51a81 100644
--- a/extras/just.sublime-syntax
+++ b/extras/just.sublime-syntax
@@ -31,7 +31,7 @@ contexts:
- match: '\}\}'
pop: true
functions:
- - match: \b(arch|os|os_family|env_var|env_var_or_default|invocation_directory|justfile|justfile_directory|just_executable|lowercase|quote|replace|trim|trim_end|trim_end_match|trim_end_matches|trim_start|trim_start_match|trim_start_matches|uppercase|absolute_path|extension|file_name|file_stem|parent_directory|without_extension|join|clean|path_exists|error|sha256|sha256_file|uuid|capitalize)\b(?=\()
+ - match: \b(arch|os|os_family|env_var|env_var_or_default|invocation_directory|justfile|justfile_directory|just_executable|lowercase|quote|replace|trim|trim_end|trim_end_match|trim_end_matches|trim_start|trim_start_match|trim_start_matches|uppercase|absolute_path|extension|file_name|file_stem|parent_directory|without_extension|join|clean|path_exists|error|sha256|sha256_file|uuid|capitalize|uppercamelcase|lowercamelcase|snakecase|kebabcase|shoutysnakecase|titlecase|shoutykebabcase)\b(?=\()
scope: entity.name.function.just
keywords:
- match: \b(if|else|while)\b
diff --git a/src/function.rs b/src/function.rs
index 445adf1..461384f 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -3,6 +3,11 @@
use super::*;
+use heck::{
+ ToKebabCase, ToLowerCamelCase, ToShoutyKebabCase, ToShoutySnakeCase, ToSnakeCase, ToTitleCase,
+ ToUpperCamelCase,
+};
+
use Function::*;
pub(crate) enum Function {
Nullary(fn(&FunctionContext) -> Result),
@@ -29,6 +34,8 @@ lazy_static! {
("just_executable", Nullary(just_executable)),
("justfile", Nullary(justfile)),
("justfile_directory", Nullary(justfile_directory)),
+ ("kebabcase", Unary(kebabcase)),
+ ("lowercamelcase", Unary(lowercamelcase)),
("lowercase", Unary(lowercase)),
("os", Nullary(os)),
("os_family", Nullary(os_family)),
@@ -38,6 +45,10 @@ lazy_static! {
("replace", Ternary(replace)),
("sha256", Unary(sha256)),
("sha256_file", Unary(sha256_file)),
+ ("shoutykebabcase", Unary(shoutykebabcase)),
+ ("shoutysnakecase", Unary(shoutysnakecase)),
+ ("snakecase", Unary(snakecase)),
+ ("titlecase", Unary(titlecase)),
("trim", Unary(trim)),
("trim_end", Unary(trim_end)),
("trim_end_match", Binary(trim_end_match)),
@@ -45,6 +56,7 @@ lazy_static! {
("trim_start", Unary(trim_start)),
("trim_start_match", Binary(trim_start_match)),
("trim_start_matches", Binary(trim_start_matches)),
+ ("uppercamelcase", Unary(uppercamelcase)),
("uppercase", Unary(uppercase)),
("uuid", Nullary(uuid)),
("without_extension", Unary(without_extension)),
@@ -225,6 +237,14 @@ fn justfile_directory(context: &FunctionContext) -> Result {
})
}
+fn kebabcase(_context: &FunctionContext, s: &str) -> Result {
+ Ok(s.to_kebab_case())
+}
+
+fn lowercamelcase(_context: &FunctionContext, s: &str) -> Result {
+ Ok(s.to_lower_camel_case())
+}
+
fn lowercase(_context: &FunctionContext, s: &str) -> Result {
Ok(s.to_lowercase())
}
@@ -283,6 +303,22 @@ fn sha256_file(context: &FunctionContext, path: &str) -> Result
Ok(format!("{:x}", hash))
}
+fn shoutykebabcase(_context: &FunctionContext, s: &str) -> Result {
+ Ok(s.to_shouty_kebab_case())
+}
+
+fn shoutysnakecase(_context: &FunctionContext, s: &str) -> Result {
+ Ok(s.to_shouty_snake_case())
+}
+
+fn snakecase(_context: &FunctionContext, s: &str) -> Result {
+ Ok(s.to_snake_case())
+}
+
+fn titlecase(_context: &FunctionContext, s: &str) -> Result {
+ Ok(s.to_title_case())
+}
+
fn trim(_context: &FunctionContext, s: &str) -> Result {
Ok(s.trim().to_owned())
}
@@ -311,6 +347,10 @@ fn trim_start_matches(_context: &FunctionContext, s: &str, pat: &str) -> Result<
Ok(s.trim_start_matches(pat).to_owned())
}
+fn uppercamelcase(_context: &FunctionContext, s: &str) -> Result {
+ Ok(s.to_upper_camel_case())
+}
+
fn uppercase(_context: &FunctionContext, s: &str) -> Result {
Ok(s.to_uppercase())
}
diff --git a/tests/functions.rs b/tests/functions.rs
index f2c2ae8..6a7ae0c 100644
--- a/tests/functions.rs
+++ b/tests/functions.rs
@@ -283,6 +283,76 @@ test! {
stderr: "echo bar\n",
}
+test! {
+ name: uppercamelcase,
+ justfile: "
+ foo:
+ echo {{ uppercamelcase('foo bar') }}
+ ",
+ stdout: "FooBar\n",
+ stderr: "echo FooBar\n",
+}
+
+test! {
+ name: lowercamelcase,
+ justfile: "
+ foo:
+ echo {{ lowercamelcase('foo bar') }}
+ ",
+ stdout: "fooBar\n",
+ stderr: "echo fooBar\n",
+}
+
+test! {
+ name: snakecase,
+ justfile: "
+ foo:
+ echo {{ snakecase('foo bar') }}
+ ",
+ stdout: "foo_bar\n",
+ stderr: "echo foo_bar\n",
+}
+
+test! {
+ name: kebabcase,
+ justfile: "
+ foo:
+ echo {{ kebabcase('foo bar') }}
+ ",
+ stdout: "foo-bar\n",
+ stderr: "echo foo-bar\n",
+}
+
+test! {
+ name: shoutysnakecase,
+ justfile: "
+ foo:
+ echo {{ shoutysnakecase('foo bar') }}
+ ",
+ stdout: "FOO_BAR\n",
+ stderr: "echo FOO_BAR\n",
+}
+
+test! {
+ name: titlecase,
+ justfile: "
+ foo:
+ echo {{ titlecase('foo bar') }}
+ ",
+ stdout: "Foo Bar\n",
+ stderr: "echo Foo Bar\n",
+}
+
+test! {
+ name: shoutykebabcase,
+ justfile: "
+ foo:
+ echo {{ shoutykebabcase('foo bar') }}
+ ",
+ stdout: "FOO-BAR\n",
+ stderr: "echo FOO-BAR\n",
+}
+
test! {
name: trim,
justfile: "