pub fn full_with_context<SI: ?Sized, CO, C, E, P, HD>(
    input: &SI,
    home_dir: HD,
    context: C
) -> Result<Cow<'_, str>, LookupError<E>> where
    SI: AsRef<str>,
    CO: AsRef<str>,
    C: FnMut(&str) -> Result<Option<CO>, E>,
    P: AsRef<Path>,
    HD: FnOnce() -> Option<P>, 
Expand description

Performs both tilde and environment expansion using the provided contexts.

home_dir and context are contexts for tilde expansion and environment expansion, respectively. See env_with_context() and tilde_with_context() for more details on them.

Unfortunately, expanding both ~ and $VARs at the same time is not that simple. First, this function has to track ownership of the data. Since all functions in this crate return Cow<str>, this function takes some precautions in order not to allocate more than necessary. In particular, if the input string contains neither tilde nor $-vars, this function will perform no allocations.

Second, if the input string starts with a variable, and the value of this variable starts with tilde, the naive approach may result into expansion of this tilde. This function avoids this.

Examples

use std::path::{PathBuf, Path};
use std::borrow::Cow;

fn home_dir() -> Option<PathBuf> { Some(Path::new("/home/user").into()) }

fn get_env(name: &str) -> Result<Option<&'static str>, &'static str> {
    match name {
        "A" => Ok(Some("a value")),
        "B" => Ok(Some("b value")),
        "T" => Ok(Some("~")),
        "E" => Err("some error"),
        _ => Ok(None)
    }
}

// Performs both tilde and environment expansions
assert_eq!(
    shellexpand::full_with_context("~/$A/$B", home_dir, get_env).unwrap(),
    "/home/user/a value/b value"
);

// Errors from environment expansion are propagated to the result
assert_eq!(
    shellexpand::full_with_context("~/$E/something", home_dir, get_env),
    Err(shellexpand::LookupError {
        var_name: "E".into(),
        cause: "some error"
    })
);

// Input without starting tilde and without variables does not cause allocations
let s = shellexpand::full_with_context("some/path", home_dir, get_env);
match s {
    Ok(Cow::Borrowed(s)) => assert_eq!(s, "some/path"),
    _ => unreachable!("the above variant is always valid")
}

// Input with a tilde inside a variable in the beginning of the string does not cause tilde
// expansion
assert_eq!(
    shellexpand::full_with_context("$T/$A/$B", home_dir, get_env).unwrap(),
    "~/a value/b value"
);