shrub_core/shell/expansion.rs
1//! Expansion support for shell instances.
2
3use std::borrow::Cow;
4
5use crate::interp::ExecutionParameters;
6use crate::{error, expansion, extensions};
7
8impl<SE: extensions::ShellExtensions> crate::Shell<SE> {
9 /// Returns the current value of the IFS variable, or the default value if
10 /// it is not set.
11 pub fn ifs(&self) -> Cow<'_, str> {
12 self.env_var("IFS")
13 .filter(|var| var.value().is_set())
14 .map_or_else(|| " \t\n".into(), |var| var.value().to_cow_str(self))
15 }
16
17 /// Returns the separator that joins the fields of `$*` and `${arr[*]}`: the
18 /// first character of IFS, or nothing at all when IFS is empty (an
19 /// unset IFS is a space).
20 pub(crate) fn ifs_joiner(&self) -> String {
21 self.ifs()
22 .chars()
23 .next()
24 .map_or_else(String::new, String::from)
25 }
26
27 /// Applies basic shell expansion to the provided string.
28 ///
29 /// # Arguments
30 ///
31 /// * `s` - The string to expand.
32 ///
33 /// # Errors
34 ///
35 /// - [`crate::error::ErrorKind::WordParseError`] if the text cannot be
36 /// parsed as a word.
37 /// - [`crate::error::ErrorKind::BadSubstitution`],
38 /// [`crate::error::ErrorKind::ExpandingUnsetVariable`] or
39 /// [`crate::error::ErrorKind::CheckedExpansionError`] if an expansion in
40 /// it fails, as with a bad substitution or an unset variable under `set
41 /// -u`.
42 /// - Any error raised by a command substitution or arithmetic expansion
43 /// inside the text.
44 pub async fn basic_expand_string<S: AsRef<str>>(
45 &mut self,
46 params: &ExecutionParameters,
47 s: S,
48 ) -> Result<String, error::Error> {
49 let result = expansion::basic_expand_word(self, params, s.as_ref()).await?;
50 Ok(result)
51 }
52
53 /// Applies full shell expansion and field splitting to the provided string;
54 /// returns a sequence of fields.
55 ///
56 /// # Arguments
57 ///
58 /// * `s` - The string to expand and split.
59 ///
60 /// # Errors
61 ///
62 /// - [`crate::error::ErrorKind::WordParseError`] if the text cannot be
63 /// parsed as a word.
64 /// - [`crate::error::ErrorKind::BadSubstitution`],
65 /// [`crate::error::ErrorKind::ExpandingUnsetVariable`] or
66 /// [`crate::error::ErrorKind::CheckedExpansionError`] if an expansion in
67 /// it fails, as with a bad substitution or an unset variable under `set
68 /// -u`.
69 /// - Any error raised by a command substitution or arithmetic expansion
70 /// inside the text.
71 pub async fn full_expand_and_split_string<S: AsRef<str>>(
72 &mut self,
73 params: &ExecutionParameters,
74 s: S,
75 ) -> Result<Vec<String>, error::Error> {
76 let result = expansion::full_expand_and_split_word(self, params, s.as_ref()).await?;
77 Ok(result)
78 }
79}