summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/formatter/model.rs39
-rw-r--r--src/formatter/string_formatter.rs83
2 files changed, 108 insertions, 14 deletions
diff --git a/src/formatter/model.rs b/src/formatter/model.rs
index 54b35aae0..27839400f 100644
--- a/src/formatter/model.rs
+++ b/src/formatter/model.rs
@@ -6,6 +6,11 @@ pub trait VariableHolder<T> {
fn get_variables(&self) -> BTreeSet<T>;
}
+/// Type that holds a number of style variables of type `T`
+pub trait StyleVariableHolder<T> {
+ fn get_style_variables(&self) -> BTreeSet<T>;
+}
+
pub struct TextGroup<'a> {
pub format: Vec<FormatElement<'a>>,
pub style: Vec<StyleElement<'a>>,
@@ -46,3 +51,37 @@ impl<'a> VariableHolder<Cow<'a, str>> for Vec<FormatElement<'a>> {
})
}
}
+
+impl<'a> StyleVariableHolder<Cow<'a, str>> for StyleElement<'a> {
+ fn get_style_variables(&self) -> BTreeSet<Cow<'a, str>> {
+ match self {
+ StyleElement::Variable(var) => {
+ let mut variables = BTreeSet::new();
+ variables.insert(var.clone());
+ variables
+ }
+ _ => Default::default(),
+ }
+ }
+}
+
+impl<'a> StyleVariableHolder<Cow<'a, str>> for Vec<StyleElement<'a>> {
+ fn get_style_variables(&self) -> BTreeSet<Cow<'a, str>> {
+ self.iter().fold(BTreeSet::new(), |mut acc, el| {
+ acc.extend(el.get_style_variables());
+ acc
+ })
+ }
+}
+
+impl<'a> StyleVariableHolder<Cow<'a, str>> for Vec<FormatElement<'a>> {
+ fn get_style_variables(&self) -> BTreeSet<Cow<'a, str>> {
+ self.iter().fold(BTreeSet::new(), |mut acc, el| match el {
+ FormatElement::TextGroup(textgroup) => {
+ acc.extend(textgroup.style.get_style_variables());
+ acc
+ }
+ _ => acc,
+ })
+ }
+}
diff --git a/src/formatter/string_formatter.rs b/src/formatter/string_formatter.rs
index a474c8efd..e7977cbdc 100644
--- a/src/formatter/string_formatter.rs
+++ b/src/formatter/string_formatter.rs
@@ -23,10 +23,12 @@ impl Default for VariableValue {
}
type VariableMapType = BTreeMap<String, Option<VariableValue>>;
+type StyleVariableMapType = BTreeMap<String, Option<String>>;
pub struct StringFormatter<'a> {
format: Vec<FormatElement<'a>>,
variables: VariableMapType,
+ style_variables: StyleVariableMapType,
}
impl<'a> StringFormatter<'a> {
@@ -42,9 +44,20 @@ impl<'a> StringFormatter<'a> {
.map(|key| (key.to_string(), None))
.collect::<Vec<(String, Option<_>)>>(),
);
- (format, variables)
+ let style_variables = StyleVariableMapType::from_iter(
+ format
+ .get_style_variables()
+ .into_iter()
+ .map(|key| (key.to_string(), None))
+ .collect::<Vec<(String, Option<_>)>>(),
+ );
+ (format, variables, style_variables)
+ })
+ .map(|(format, variables, style_variables)| Self {
+ format,
+ variables,
+ style_variables,
})
- .map(|(format, variables)| Self { format, variables })
}
/// Maps variable name to its value
@@ -66,27 +79,41 @@ impl<'a> StringFormatter<'a> {
self
}
+ /// Maps variable name in a style string to its value
+ pub fn map_style(mut self, mapper: impl Fn(&str) -> Option<String> + Sync) -> Self {
+ self.style_variables
+ .par_iter_mut()
+ .for_each(|(key, value)| {
+ *value = mapper(key);
+ });
+ self
+ }
+
/// Parse the format string and consume self.
pub fn parse(self, default_style: Option<Style>) -> Vec<Segment> {
fn _parse_textgroup<'a>(
textgroup: TextGroup<'a>,
variables: &'a VariableMapType,
+ style_variables: &'a StyleVariableMapType,
) -> Vec<Segment> {
- let style = _parse_style(textgroup.style);
- _parse_format(textgroup.format, style, &variables)
+ let style = _parse_style(textgroup.style, style_variables);
+ _parse_format(textgroup.format, style, &variables, &style_variables)
}
- fn _parse_style(style: Vec<StyleElement>) -> Option<Style> {
+ fn _parse_style<'a>(
+ style: Vec<StyleElement>,
+ variables: &'a StyleVariableMapType,
+ ) -> Option<Style> {
let style_string = style
.iter()
.flat_map(|style| match style {
StyleElement::Text(text) => text.as_ref().chars(),
- StyleElement::Variable(variable) => {
- log::warn!(
- "Variable `{}` monitored in style string, which is not allowed",
- &variable
- );
- "".chars()
+ StyleElement::Variable(name) => {
+ let variable = variables.get(name.as_ref()).unwrap_or(&None);
+ match variable {
+ Some(style_string) => style_string.chars(),
+ None => "".chars(),
+ }
}
})
.collect::<String>();
@@ -97,6 +124,7 @@ impl<'a> StringFormatter<'a> {
format: Vec<FormatElement<'a>>,
style: Option<Style>,
variables: &'a VariableMapType,
+ style_variables: &'a StyleVariableMapType,
) -> Vec<Segment> {
format
.into_iter()
@@ -109,7 +137,7 @@ impl<'a> StringFormatter<'a> {
format: textgroup.format,
style: textgroup.style,
};
- _parse_textgroup(textgroup, &variables)
+ _parse_textgroup(textgroup, &variables, &style_variables)
}
FormatElement::Variable(name) => variables
.get(name.as_ref())
@@ -144,7 +172,7 @@ impl<'a> StringFormatter<'a> {
});
if should_show {
- _parse_format(format, style, variables)
+ _parse_format(format, style, variables, style_variables)
} else {
Vec::new()
}
@@ -153,7 +181,12 @@ impl<'a> StringFormatter<'a> {
.collect()
}
- _parse_format(self.format, default_style, &self.variables)
+ _parse_format(
+ self.format,
+ default_style,
+ &self.variables,
+ &self.style_variables,
+ )
}
}
@@ -163,6 +196,12 @@ impl<'a> VariableHolder<String> for StringFormatter<'a> {
}
}
+impl<'a> StyleVariableHolder<String> for StringFormatter<'a> {
+ fn get_style_variables(&self) -> BTreeSet<String> {
+ BTreeSet::from_iter(self.style_variables.keys().cloned())
+ }
+}
+
/// Helper function to create a new segment
fn _new_segment(name: String, value: String, style: Option<Style>) -> Segment {
Segment {
@@ -226,6 +265,22 @@ mod tests {
}
#[test]
+ fn test_variable_in_style() {
+ const FORMAT_STR: &str = "[root]($style)";
+ let root_style = Some(Color::Red.bold());
+
+ let formatter = StringFormatter::new(FORMAT_STR)
+ .unwrap()
+ .map_style(|variable| match variable {
+ "style" => Some("red bold".to_owned()),
+ _ => None,
+ });
+ let result = formatter.parse(None);
+ let mut result_iter = result.iter();
+ match_next!(result_iter, "root", root_style);
+ }
+
+ #[test]
fn test_scoped_variable() {
const FORMAT_STR: &str = "${env:PWD}";