diff --git a/README.adoc b/README.adoc index 17a7ef0..1b00187 100644 --- a/README.adoc +++ b/README.adoc @@ -794,14 +794,22 @@ Starting server with database localhost:6379 on port 1337... ==== Path Manipulation -- `file_name(path)` - File name of `path` with any leading directory components removed. `file_name("/foo/bar.txt")` is `bar.txt`. -- `parent_directory(path)` - Parent directory of `path`. `parent_directory("/foo/bar.txt")` is `/foo`. -- `file_stem(path)` - File name of `path` without extension. `file_stem("/foo/bar.txt")` is `bar`. -- `without_extension(path)` - `path` without extension. `without_extension("/foo/bar.txt")` is `/foo/bar`. +===== Fallible + - `extension(path)` - Extension of `path`. `extension("/foo/bar.txt")` is `txt`. +- `file_name(path)` - File name of `path` with any leading directory components removed. `file_name("/foo/bar.txt")` is `bar.txt`. +- `file_stem(path)` - File name of `path` without extension. `file_stem("/foo/bar.txt")` is `bar`. +- `parent_directory(path)` - Parent directory of `path`. `parent_directory("/foo/bar.txt")` is `/foo`. +- `without_extension(path)` - `path` without extension. `without_extension("/foo/bar.txt")` is `/foo/bar`. These functions can fail, for example if a path does not have an extension, which will halt execution. +===== Infallible + +- `join(a, b)` - Join path `a` with path `b`. `join("foo/bar", "baz")` is `foo/bar/baz`. + +These functions always succeed. + === Command Evaluation Using Backticks Backticks can be used to store the result of commands: diff --git a/src/function.rs b/src/function.rs index 3612731..eabeb38 100644 --- a/src/function.rs +++ b/src/function.rs @@ -10,19 +10,20 @@ pub(crate) enum Function { lazy_static! { pub(crate) static ref TABLE: BTreeMap<&'static str, Function> = vec![ ("arch", Nullary(arch)), - ("os", Nullary(os)), - ("os_family", Nullary(os_family)), - ("justfile_directory", Nullary(justfile_directory)), - ("justfile", Nullary(justfile)), - ("invocation_directory", Nullary(invocation_directory)), ("env_var", Unary(env_var)), ("env_var_or_default", Binary(env_var_or_default)), - ("just_executable", Nullary(just_executable)), + ("extension", Unary(extension)), ("file_name", Unary(file_name)), - ("parent_directory", Unary(parent_directory)), ("file_stem", Unary(file_stem)), + ("invocation_directory", Nullary(invocation_directory)), + ("join", Binary(join)), + ("just_executable", Nullary(just_executable)), + ("justfile", Nullary(justfile)), + ("justfile_directory", Nullary(justfile_directory)), + ("os", Nullary(os)), + ("os_family", Nullary(os_family)), + ("parent_directory", Unary(parent_directory)), ("without_extension", Unary(without_extension)), - ("extension", Unary(extension)) ] .into_iter() .collect(); @@ -42,55 +43,6 @@ fn arch(_context: &FunctionContext) -> Result { Ok(target::arch().to_owned()) } -fn os(_context: &FunctionContext) -> Result { - Ok(target::os().to_owned()) -} - -fn os_family(_context: &FunctionContext) -> Result { - Ok(target::os_family().to_owned()) -} - -fn invocation_directory(context: &FunctionContext) -> Result { - Platform::convert_native_path( - &context.search.working_directory, - context.invocation_directory, - ) - .map_err(|e| format!("Error getting shell path: {}", e)) -} - -fn justfile(context: &FunctionContext) -> Result { - context - .search - .justfile - .to_str() - .map(str::to_owned) - .ok_or_else(|| { - format!( - "Justfile path is not valid unicode: {}", - context.search.justfile.to_string_lossy() - ) - }) -} - -fn justfile_directory(context: &FunctionContext) -> Result { - let justfile_directory = context.search.justfile.parent().ok_or_else(|| { - format!( - "Could not resolve justfile directory. Justfile `{}` had no parent.", - context.search.justfile.display() - ) - })?; - - justfile_directory - .to_str() - .map(str::to_owned) - .ok_or_else(|| { - format!( - "Justfile directory is not valid unicode: {}", - justfile_directory.to_string_lossy() - ) - }) -} - fn env_var(context: &FunctionContext, key: &str) -> Result { use std::env::VarError::*; @@ -129,6 +81,39 @@ fn env_var_or_default( } } +fn extension(_context: &FunctionContext, path: &str) -> Result { + Utf8Path::new(path) + .extension() + .map(str::to_owned) + .ok_or_else(|| format!("Could not extract extension from `{}`", path)) +} + +fn file_name(_context: &FunctionContext, path: &str) -> Result { + Utf8Path::new(path) + .file_name() + .map(str::to_owned) + .ok_or_else(|| format!("Could not extract file name from `{}`", path)) +} + +fn file_stem(_context: &FunctionContext, path: &str) -> Result { + Utf8Path::new(path) + .file_stem() + .map(str::to_owned) + .ok_or_else(|| format!("Could not extract file stem from `{}`", path)) +} + +fn invocation_directory(context: &FunctionContext) -> Result { + Platform::convert_native_path( + &context.search.working_directory, + context.invocation_directory, + ) + .map_err(|e| format!("Error getting shell path: {}", e)) +} + +fn join(_context: &FunctionContext, base: &str, with: &str) -> Result { + Ok(Utf8Path::new(base).join(with).to_string()) +} + fn just_executable(_context: &FunctionContext) -> Result { let exe_path = std::env::current_exe().map_err(|e| format!("Error getting current executable: {}", e))?; @@ -141,11 +126,45 @@ fn just_executable(_context: &FunctionContext) -> Result { }) } -fn file_name(_context: &FunctionContext, path: &str) -> Result { - Utf8Path::new(path) - .file_name() +fn justfile(context: &FunctionContext) -> Result { + context + .search + .justfile + .to_str() .map(str::to_owned) - .ok_or_else(|| format!("Could not extract file name from `{}`", path)) + .ok_or_else(|| { + format!( + "Justfile path is not valid unicode: {}", + context.search.justfile.to_string_lossy() + ) + }) +} + +fn justfile_directory(context: &FunctionContext) -> Result { + let justfile_directory = context.search.justfile.parent().ok_or_else(|| { + format!( + "Could not resolve justfile directory. Justfile `{}` had no parent.", + context.search.justfile.display() + ) + })?; + + justfile_directory + .to_str() + .map(str::to_owned) + .ok_or_else(|| { + format!( + "Justfile directory is not valid unicode: {}", + justfile_directory.to_string_lossy() + ) + }) +} + +fn os(_context: &FunctionContext) -> Result { + Ok(target::os().to_owned()) +} + +fn os_family(_context: &FunctionContext) -> Result { + Ok(target::os_family().to_owned()) } fn parent_directory(_context: &FunctionContext, path: &str) -> Result { @@ -155,13 +174,6 @@ fn parent_directory(_context: &FunctionContext, path: &str) -> Result Result { - Utf8Path::new(path) - .file_stem() - .map(str::to_owned) - .ok_or_else(|| format!("Could not extract file stem from `{}`", path)) -} - fn without_extension(_context: &FunctionContext, path: &str) -> Result { let parent = Utf8Path::new(path) .parent() @@ -173,10 +185,3 @@ fn without_extension(_context: &FunctionContext, path: &str) -> Result Result { - Utf8Path::new(path) - .extension() - .map(str::to_owned) - .ok_or_else(|| format!("Could not extract extension from `{}`", path)) -} diff --git a/tests/misc.rs b/tests/misc.rs index d638905..ac93317 100644 --- a/tests/misc.rs +++ b/tests/misc.rs @@ -1179,12 +1179,13 @@ fs := file_stem('/foo/bar/baz.hello') fn := file_name('/foo/bar/baz.hello') dir := parent_directory('/foo/bar/baz.hello') ext := extension('/foo/bar/baz.hello') +jn := join('a', 'b') foo: - /bin/echo '{{we}}' '{{fs}}' '{{fn}}' '{{dir}}' '{{ext}}' + /bin/echo '{{we}}' '{{fs}}' '{{fn}}' '{{dir}}' '{{ext}}' '{{jn}}' "#, - stdout: "/foo/bar/baz baz baz.hello /foo/bar hello\n", - stderr: "/bin/echo '/foo/bar/baz' 'baz' 'baz.hello' '/foo/bar' 'hello'\n", + stdout: "/foo/bar/baz baz baz.hello /foo/bar hello a/b\n", + stderr: "/bin/echo '/foo/bar/baz' 'baz' 'baz.hello' '/foo/bar' 'hello' 'a/b'\n", } #[cfg(not(windows))]