shellexpand/
lib.rs

1//! Provides functions for performing shell-like expansions in strings.
2//!
3//! In particular, the following expansions are supported:
4//!
5//! * tilde expansion, when `~` in the beginning of a string, like in `"~/some/path"`,
6//!   is expanded into the home directory of the current user;
7//! * environment expansion, when `$A` or `${B}`, like in `"~/$A/${B}something"`,
8//!   are expanded into their values in some environment.
9//!
10//! Environment expansion also supports default values with the familiar shell syntax,
11//! so for example `${UNSET_ENV:-42}` will use the specified default value, i.e. `42`, if
12//! the `UNSET_ENV` variable is not set in the environment.
13//!
14//! The source of external information for these expansions (home directory and environment
15//! variables) is called their *context*. The context is provided to these functions as a closure
16//! of the respective type.
17//!
18//! This crate provides both customizable functions, which require their context to be provided
19//! explicitly, and wrapper functions which use [`dirs::home_dir()`] and [`std::env::var()`]
20//! for obtaining home directory and environment variables, respectively.
21//!
22//! Also there is a "full" function which performs both tilde and environment
23//! expansion, but does it correctly, rather than just doing one after another: for example,
24//! if the string starts with a variable whose value starts with a `~`, then this tilde
25//! won't be expanded.
26//!
27//! All functions return [`Cow<str>`][Cow] because it is possible for their input not to contain anything
28//! which triggers the expansion. In that case performing allocations can be avoided.
29//!
30//! Please note that by default unknown variables in environment expansion are left as they are
31//! and are not, for example, substituted with an empty string:
32//!
33//! ```
34//! fn context(_: &str) -> Option<String> { None }
35//!
36//! assert_eq!(
37//!     shellexpand::env_with_context_no_errors("$A $B", context),
38//!     "$A $B"
39//! );
40//! ```
41//!
42//! Environment expansion context allows for a very fine tweaking of how results should be handled,
43//! so it is up to the user to pass a context function which does the necessary thing. For example,
44//! [`env()`] and [`full()`] functions from this library pass all errors returned by [`std::env::var()`]
45//! through, therefore they will also return an error if some unknown environment
46//! variable is used, because [`std::env::var()`] returns an error in this case:
47//!
48//! ```
49//! use std::env;
50//!
51//! // make sure that the variable indeed does not exist
52//! env::remove_var("MOST_LIKELY_NONEXISTING_VAR");
53//!
54//! assert_eq!(
55//!     shellexpand::env("$MOST_LIKELY_NONEXISTING_VAR"),
56//!     Err(shellexpand::LookupError {
57//!         var_name: "MOST_LIKELY_NONEXISTING_VAR".into(),
58//!         cause: env::VarError::NotPresent
59//!     })
60//! );
61//! ```
62//!
63//! The author thinks that this approach is more useful than just substituting an empty string
64//! (like, for example, does Go with its [os.ExpandEnv](https://golang.org/pkg/os/#ExpandEnv)
65//! function), but if you do need `os.ExpandEnv`-like behavior, it is fairly easy to get one:
66//!
67//! ```
68//! use std::env;
69//! use std::borrow::Cow;
70//!
71//! fn context(s: &str) -> Result<Option<Cow<'static, str>>, env::VarError> {
72//!     match env::var(s) {
73//!         Ok(value) => Ok(Some(value.into())),
74//!         Err(env::VarError::NotPresent) => Ok(Some("".into())),
75//!         Err(e) => Err(e)
76//!     }
77//! }
78//!
79//! // make sure that the variable indeed does not exist
80//! env::remove_var("MOST_LIKELY_NONEXISTING_VAR");
81//!
82//! assert_eq!(
83//!     shellexpand::env_with_context("a${MOST_LIKELY_NOEXISTING_VAR}b", context).unwrap(),
84//!     "ab"
85//! );
86//! ```
87//!
88//! The above example also demonstrates the flexibility of context function signatures: the context
89//! function may return anything which can be `AsRef`ed into a string slice.
90//!
91//! [Cow]: std::borrow::Cow
92
93mod strings;
94pub use self::strings::funcs::*;
95
96#[cfg(feature = "path")]
97pub mod path;
98
99#[cfg(not(feature = "base-0"))]
100compile_error!("You must enable the base-0 feature.  See the crate-level README.");