Add docs for json values and make value related names shorter
This commit is contained in:
parent
ce4c22e2a6
commit
aaac4c3b43
16 changed files with 223 additions and 221 deletions
|
@ -32,4 +32,6 @@ The expression language supports:
|
||||||
- conditionals (`if condition then 'value' else 'other value'`)
|
- conditionals (`if condition then 'value' else 'other value'`)
|
||||||
- numbers, strings, booleans and variable references (`12`, `'hi'`, `true`, `some_variable`)
|
- numbers, strings, booleans and variable references (`12`, `'hi'`, `true`, `some_variable`)
|
||||||
- strings can contain other expressions again: `'foo {{some_variable}} bar'`
|
- strings can contain other expressions again: `'foo {{some_variable}} bar'`
|
||||||
|
- json access (`object.field`, `array[12]`, `object["field"]`)
|
||||||
|
- for this, the object/array value needs to refer to a variable that contains a valid json string.
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
config::{window_definition::WindowName, AnchorPoint, WindowStacking},
|
config::{window_definition::WindowName, AnchorPoint, WindowStacking},
|
||||||
display_backend, eww_state,
|
display_backend, eww_state,
|
||||||
script_var_handler::*,
|
script_var_handler::*,
|
||||||
value::{Coords, NumWithUnit, PrimitiveValue, VarName},
|
value::{Coords, NumWithUnit, PrimVal, VarName},
|
||||||
EwwPaths,
|
EwwPaths,
|
||||||
};
|
};
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
|
@ -41,7 +41,7 @@ pub type DaemonResponseReceiver = tokio::sync::mpsc::UnboundedReceiver<DaemonRes
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DaemonCommand {
|
pub enum DaemonCommand {
|
||||||
NoOp,
|
NoOp,
|
||||||
UpdateVars(Vec<(VarName, PrimitiveValue)>),
|
UpdateVars(Vec<(VarName, PrimVal)>),
|
||||||
ReloadConfigAndCss(DaemonResponseSender),
|
ReloadConfigAndCss(DaemonResponseSender),
|
||||||
UpdateConfig(config::EwwConfig),
|
UpdateConfig(config::EwwConfig),
|
||||||
UpdateCss(String),
|
UpdateCss(String),
|
||||||
|
@ -193,7 +193,7 @@ impl App {
|
||||||
gtk::main_quit();
|
gtk::main_quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_state(&mut self, fieldname: VarName, value: PrimitiveValue) {
|
fn update_state(&mut self, fieldname: VarName, value: PrimVal) {
|
||||||
self.eww_state.update_variable(fieldname, value)
|
self.eww_state.update_variable(fieldname, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use regex::Regex;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
value::{AttrName, AttrValue},
|
value::{AttrName, AttrVal},
|
||||||
with_text_pos_context,
|
with_text_pos_context,
|
||||||
};
|
};
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
|
@ -41,7 +41,7 @@ impl WidgetDefinition {
|
||||||
pub struct WidgetUse {
|
pub struct WidgetUse {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub children: Vec<WidgetUse>,
|
pub children: Vec<WidgetUse>,
|
||||||
pub attrs: HashMap<AttrName, AttrValue>,
|
pub attrs: HashMap<AttrName, AttrVal>,
|
||||||
pub text_pos: Option<TextPos>,
|
pub text_pos: Option<TextPos>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ impl WidgetUse {
|
||||||
};
|
};
|
||||||
let text_pos = xml.text_pos();
|
let text_pos = xml.text_pos();
|
||||||
let widget_use = match xml {
|
let widget_use = match xml {
|
||||||
XmlNode::Text(text) => WidgetUse::simple_text(AttrValue::parse_string(&text.text())),
|
XmlNode::Text(text) => WidgetUse::simple_text(AttrVal::parse_string(&text.text())),
|
||||||
XmlNode::Element(elem) => WidgetUse {
|
XmlNode::Element(elem) => WidgetUse {
|
||||||
name: elem.tag_name().to_owned(),
|
name: elem.tag_name().to_owned(),
|
||||||
children: with_text_pos_context! { elem => elem.children().map(WidgetUse::from_xml_node).collect::<Result<_>>()?}?,
|
children: with_text_pos_context! { elem => elem.children().map(WidgetUse::from_xml_node).collect::<Result<_>>()?}?,
|
||||||
|
@ -77,7 +77,7 @@ impl WidgetUse {
|
||||||
.map(|attr| {
|
.map(|attr| {
|
||||||
(
|
(
|
||||||
AttrName(attr.name().to_owned()),
|
AttrName(attr.name().to_owned()),
|
||||||
AttrValue::parse_string(&xml_ext::resolve_escaped_symbols(&attr.value())),
|
AttrVal::parse_string(&xml_ext::resolve_escaped_symbols(&attr.value())),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<HashMap<_, _>>(),
|
.collect::<HashMap<_, _>>(),
|
||||||
|
@ -88,7 +88,7 @@ impl WidgetUse {
|
||||||
Ok(widget_use.at_pos(text_pos))
|
Ok(widget_use.at_pos(text_pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn simple_text(text: AttrValue) -> Self {
|
pub fn simple_text(text: AttrVal) -> Self {
|
||||||
WidgetUse {
|
WidgetUse {
|
||||||
name: "label".to_owned(),
|
name: "label".to_owned(),
|
||||||
children: vec![],
|
children: vec![],
|
||||||
|
@ -111,7 +111,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_simple_text() {
|
fn test_simple_text() {
|
||||||
let expected_attr_value = AttrValue::from_primitive("my text");
|
let expected_attr_value = AttrVal::from_primitive("my text");
|
||||||
let widget = WidgetUse::simple_text(expected_attr_value.clone());
|
let widget = WidgetUse::simple_text(expected_attr_value.clone());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
widget,
|
widget,
|
||||||
|
@ -138,12 +138,12 @@ mod test {
|
||||||
let expected = WidgetUse {
|
let expected = WidgetUse {
|
||||||
name: "widget_name".to_owned(),
|
name: "widget_name".to_owned(),
|
||||||
attrs: hashmap! {
|
attrs: hashmap! {
|
||||||
AttrName("attr1".to_owned()) => AttrValue::from_primitive("hi"),
|
AttrName("attr1".to_owned()) => AttrVal::from_primitive("hi"),
|
||||||
AttrName("attr2".to_owned()) => AttrValue::from_primitive("12"),
|
AttrName("attr2".to_owned()) => AttrVal::from_primitive("12"),
|
||||||
},
|
},
|
||||||
children: vec![
|
children: vec![
|
||||||
WidgetUse::new("child_widget".to_owned(), Vec::new()),
|
WidgetUse::new("child_widget".to_owned(), Vec::new()),
|
||||||
WidgetUse::simple_text(AttrValue::from_primitive("foo".to_owned())),
|
WidgetUse::simple_text(AttrVal::from_primitive("foo".to_owned())),
|
||||||
],
|
],
|
||||||
..WidgetUse::default()
|
..WidgetUse::default()
|
||||||
};
|
};
|
||||||
|
@ -165,7 +165,7 @@ mod test {
|
||||||
size: Some((12, 20)),
|
size: Some((12, 20)),
|
||||||
structure: WidgetUse {
|
structure: WidgetUse {
|
||||||
name: "layout".to_owned(),
|
name: "layout".to_owned(),
|
||||||
children: vec![WidgetUse::simple_text(AttrValue::from_primitive("test"))],
|
children: vec![WidgetUse::simple_text(AttrVal::from_primitive("test"))],
|
||||||
attrs: HashMap::new(),
|
attrs: HashMap::new(),
|
||||||
..WidgetUse::default()
|
..WidgetUse::default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
util,
|
util,
|
||||||
value::{PrimitiveValue, VarName},
|
value::{PrimVal, VarName},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -18,7 +18,7 @@ use std::path::PathBuf;
|
||||||
pub struct EwwConfig {
|
pub struct EwwConfig {
|
||||||
widgets: HashMap<String, WidgetDefinition>,
|
widgets: HashMap<String, WidgetDefinition>,
|
||||||
windows: HashMap<WindowName, EwwWindowDefinition>,
|
windows: HashMap<WindowName, EwwWindowDefinition>,
|
||||||
initial_variables: HashMap<VarName, PrimitiveValue>,
|
initial_variables: HashMap<VarName, PrimVal>,
|
||||||
script_vars: HashMap<VarName, ScriptVar>,
|
script_vars: HashMap<VarName, ScriptVar>,
|
||||||
pub filepath: PathBuf,
|
pub filepath: PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ impl EwwConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this is kinda ugly
|
// TODO this is kinda ugly
|
||||||
pub fn generate_initial_state(&self) -> Result<HashMap<VarName, PrimitiveValue>> {
|
pub fn generate_initial_state(&self) -> Result<HashMap<VarName, PrimVal>> {
|
||||||
let mut vars =
|
let mut vars =
|
||||||
self.script_vars.iter().map(|var| Ok((var.0.clone(), var.1.initial_value()?))).collect::<Result<HashMap<_, _>>>()?;
|
self.script_vars.iter().map(|var| Ok((var.0.clone(), var.1.initial_value()?))).collect::<Result<HashMap<_, _>>>()?;
|
||||||
vars.extend(self.initial_variables.clone());
|
vars.extend(self.initial_variables.clone());
|
||||||
|
@ -73,7 +73,7 @@ impl EwwConfig {
|
||||||
pub struct RawEwwConfig {
|
pub struct RawEwwConfig {
|
||||||
widgets: HashMap<String, WidgetDefinition>,
|
widgets: HashMap<String, WidgetDefinition>,
|
||||||
windows: HashMap<WindowName, RawEwwWindowDefinition>,
|
windows: HashMap<WindowName, RawEwwWindowDefinition>,
|
||||||
initial_variables: HashMap<VarName, PrimitiveValue>,
|
initial_variables: HashMap<VarName, PrimVal>,
|
||||||
script_vars: HashMap<VarName, ScriptVar>,
|
script_vars: HashMap<VarName, ScriptVar>,
|
||||||
pub filepath: PathBuf,
|
pub filepath: PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -181,14 +181,14 @@ impl RawEwwConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_variables_block(xml: XmlElement) -> Result<(HashMap<VarName, PrimitiveValue>, HashMap<VarName, ScriptVar>)> {
|
fn parse_variables_block(xml: XmlElement) -> Result<(HashMap<VarName, PrimVal>, HashMap<VarName, ScriptVar>)> {
|
||||||
let mut normal_vars = HashMap::new();
|
let mut normal_vars = HashMap::new();
|
||||||
let mut script_vars = HashMap::new();
|
let mut script_vars = HashMap::new();
|
||||||
for node in xml.child_elements() {
|
for node in xml.child_elements() {
|
||||||
match node.tag_name() {
|
match node.tag_name() {
|
||||||
"var" => {
|
"var" => {
|
||||||
let value = node.only_child().map(|c| c.as_text_or_sourcecode()).unwrap_or_else(|_| String::new());
|
let value = node.only_child().map(|c| c.as_text_or_sourcecode()).unwrap_or_else(|_| String::new());
|
||||||
normal_vars.insert(VarName(node.attr("name")?.to_owned()), PrimitiveValue::from_string(value));
|
normal_vars.insert(VarName(node.attr("name")?.to_owned()), PrimVal::from_string(value));
|
||||||
}
|
}
|
||||||
"script-var" => {
|
"script-var" => {
|
||||||
let script_var = ScriptVar::from_xml_element(node)?;
|
let script_var = ScriptVar::from_xml_element(node)?;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
util,
|
util,
|
||||||
value::{PrimitiveValue, VarName},
|
value::{PrimVal, VarName},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub struct PollScriptVar {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PollScriptVar {
|
impl PollScriptVar {
|
||||||
pub fn run_once(&self) -> Result<PrimitiveValue> {
|
pub fn run_once(&self) -> Result<PrimVal> {
|
||||||
run_command(&self.command)
|
run_command(&self.command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,12 +39,12 @@ impl ScriptVar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initial_value(&self) -> Result<PrimitiveValue> {
|
pub fn initial_value(&self) -> Result<PrimVal> {
|
||||||
match self {
|
match self {
|
||||||
ScriptVar::Poll(x) => {
|
ScriptVar::Poll(x) => {
|
||||||
run_command(&x.command).with_context(|| format!("Failed to compute initial value for {}", &self.name()))
|
run_command(&x.command).with_context(|| format!("Failed to compute initial value for {}", &self.name()))
|
||||||
}
|
}
|
||||||
ScriptVar::Tail(_) => Ok(PrimitiveValue::from_string(String::new())),
|
ScriptVar::Tail(_) => Ok(PrimVal::from_string(String::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,9 +63,9 @@ impl ScriptVar {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run a command and get the output
|
/// Run a command and get the output
|
||||||
fn run_command(cmd: &str) -> Result<PrimitiveValue> {
|
fn run_command(cmd: &str) -> Result<PrimVal> {
|
||||||
log::debug!("Running command: {}", cmd);
|
log::debug!("Running command: {}", cmd);
|
||||||
let output = String::from_utf8(Command::new("/bin/sh").arg("-c").arg(cmd).output()?.stdout)?;
|
let output = String::from_utf8(Command::new("/bin/sh").arg("-c").arg(cmd).output()?.stdout)?;
|
||||||
let output = output.trim_matches('\n');
|
let output = output.trim_matches('\n');
|
||||||
Ok(PrimitiveValue::from(output))
|
Ok(PrimVal::from(output))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::window_definition::WindowName,
|
config::window_definition::WindowName,
|
||||||
value::{AttrName, AttrValueElement, VarName},
|
value::{AttrName, AttrValElement, VarName},
|
||||||
};
|
};
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use crate::value::{AttrValue, PrimitiveValue};
|
use crate::value::{AttrVal, PrimVal};
|
||||||
|
|
||||||
/// Handler that gets executed to apply the necessary parts of the eww state to
|
/// Handler that gets executed to apply the necessary parts of the eww state to
|
||||||
/// a gtk widget. These are created and initialized in EwwState::resolve.
|
/// a gtk widget. These are created and initialized in EwwState::resolve.
|
||||||
pub struct StateChangeHandler {
|
pub struct StateChangeHandler {
|
||||||
func: Box<dyn Fn(HashMap<AttrName, PrimitiveValue>) -> Result<()> + 'static>,
|
func: Box<dyn Fn(HashMap<AttrName, PrimVal>) -> Result<()> + 'static>,
|
||||||
unresolved_values: HashMap<AttrName, AttrValue>,
|
unresolved_values: HashMap<AttrName, AttrVal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StateChangeHandler {
|
impl StateChangeHandler {
|
||||||
|
@ -21,7 +21,7 @@ impl StateChangeHandler {
|
||||||
|
|
||||||
/// Run the StateChangeHandler.
|
/// Run the StateChangeHandler.
|
||||||
/// [`state`] should be the global [EwwState::state].
|
/// [`state`] should be the global [EwwState::state].
|
||||||
fn run_with_state(&self, state: &HashMap<VarName, PrimitiveValue>) {
|
fn run_with_state(&self, state: &HashMap<VarName, PrimVal>) {
|
||||||
let resolved_attrs = self
|
let resolved_attrs = self
|
||||||
.unresolved_values
|
.unresolved_values
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -61,7 +61,7 @@ impl EwwWindowState {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct EwwState {
|
pub struct EwwState {
|
||||||
windows: HashMap<WindowName, EwwWindowState>,
|
windows: HashMap<WindowName, EwwWindowState>,
|
||||||
variables_state: HashMap<VarName, PrimitiveValue>,
|
variables_state: HashMap<VarName, PrimVal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for EwwState {
|
impl std::fmt::Debug for EwwState {
|
||||||
|
@ -71,11 +71,11 @@ impl std::fmt::Debug for EwwState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EwwState {
|
impl EwwState {
|
||||||
pub fn from_default_vars(defaults: HashMap<VarName, PrimitiveValue>) -> Self {
|
pub fn from_default_vars(defaults: HashMap<VarName, PrimVal>) -> Self {
|
||||||
EwwState { variables_state: defaults, ..EwwState::default() }
|
EwwState { variables_state: defaults, ..EwwState::default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_variables(&self) -> &HashMap<VarName, PrimitiveValue> {
|
pub fn get_variables(&self) -> &HashMap<VarName, PrimVal> {
|
||||||
&self.variables_state
|
&self.variables_state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ impl EwwState {
|
||||||
|
|
||||||
/// Update the value of a variable, running all registered
|
/// Update the value of a variable, running all registered
|
||||||
/// [StateChangeHandler]s.
|
/// [StateChangeHandler]s.
|
||||||
pub fn update_variable(&mut self, key: VarName, value: PrimitiveValue) {
|
pub fn update_variable(&mut self, key: VarName, value: PrimVal) {
|
||||||
self.variables_state.insert(key.clone(), value);
|
self.variables_state.insert(key.clone(), value);
|
||||||
|
|
||||||
// run all of the handlers
|
// run all of the handlers
|
||||||
|
@ -103,27 +103,27 @@ impl EwwState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Look up a single variable in the eww state, returning an `Err` when the value is not found.
|
/// Look up a single variable in the eww state, returning an `Err` when the value is not found.
|
||||||
pub fn lookup(&self, var_name: &VarName) -> Result<&PrimitiveValue> {
|
pub fn lookup(&self, var_name: &VarName) -> Result<&PrimVal> {
|
||||||
self.variables_state.get(var_name).with_context(|| format!("Unknown variable '{}' referenced", var_name))
|
self.variables_state.get(var_name).with_context(|| format!("Unknown variable '{}' referenced", var_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// resolves a value if possible, using the current eww_state.
|
/// resolves a value if possible, using the current eww_state.
|
||||||
pub fn resolve_once<'a>(&'a self, value: &'a AttrValue) -> Result<PrimitiveValue> {
|
pub fn resolve_once<'a>(&'a self, value: &'a AttrVal) -> Result<PrimVal> {
|
||||||
value
|
value
|
||||||
.iter()
|
.iter()
|
||||||
.map(|element| match element {
|
.map(|element| match element {
|
||||||
AttrValueElement::Primitive(primitive) => Ok(primitive.clone()),
|
AttrValElement::Primitive(primitive) => Ok(primitive.clone()),
|
||||||
AttrValueElement::Expr(expr) => expr.clone().eval(&self.variables_state),
|
AttrValElement::Expr(expr) => expr.clone().eval(&self.variables_state),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve takes a function that applies a set of fully resolved attribute
|
/// Resolve takes a function that applies a set of fully resolved attribute
|
||||||
/// values to it's gtk widget.
|
/// values to it's gtk widget.
|
||||||
pub fn resolve<F: Fn(HashMap<AttrName, PrimitiveValue>) -> Result<()> + 'static + Clone>(
|
pub fn resolve<F: Fn(HashMap<AttrName, PrimVal>) -> Result<()> + 'static + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
window_name: &WindowName,
|
window_name: &WindowName,
|
||||||
required_attributes: HashMap<AttrName, AttrValue>,
|
required_attributes: HashMap<AttrName, AttrVal>,
|
||||||
set_value: F,
|
set_value: F,
|
||||||
) {
|
) {
|
||||||
let handler = StateChangeHandler { func: Box::new(set_value), unresolved_values: required_attributes };
|
let handler = StateChangeHandler { func: Box::new(set_value), unresolved_values: required_attributes };
|
||||||
|
|
|
@ -5,7 +5,7 @@ use structopt::StructOpt;
|
||||||
use crate::{
|
use crate::{
|
||||||
app,
|
app,
|
||||||
config::{AnchorPoint, WindowName},
|
config::{AnchorPoint, WindowName},
|
||||||
value::{Coords, PrimitiveValue, VarName},
|
value::{Coords, PrimVal, VarName},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Struct that gets generated from `RawOpt`.
|
/// Struct that gets generated from `RawOpt`.
|
||||||
|
@ -61,7 +61,7 @@ pub enum ActionWithServer {
|
||||||
Update {
|
Update {
|
||||||
/// variable_name="new_value"-pairs that will be updated
|
/// variable_name="new_value"-pairs that will be updated
|
||||||
#[structopt(parse(try_from_str = parse_var_update_arg))]
|
#[structopt(parse(try_from_str = parse_var_update_arg))]
|
||||||
mappings: Vec<(VarName, PrimitiveValue)>,
|
mappings: Vec<(VarName, PrimVal)>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// open a window
|
/// open a window
|
||||||
|
@ -138,11 +138,11 @@ impl From<RawOpt> for Opt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_var_update_arg(s: &str) -> Result<(VarName, PrimitiveValue)> {
|
fn parse_var_update_arg(s: &str) -> Result<(VarName, PrimVal)> {
|
||||||
let (name, value) = s
|
let (name, value) = s
|
||||||
.split_once('=')
|
.split_once('=')
|
||||||
.with_context(|| format!("arguments must be in the shape `variable_name=\"new_value\"`, but got: {}", s))?;
|
.with_context(|| format!("arguments must be in the shape `variable_name=\"new_value\"`, but got: {}", s))?;
|
||||||
Ok((name.into(), PrimitiveValue::from_string(value.to_owned())))
|
Ok((name.into(), PrimVal::from_string(value.to_owned())))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActionWithServer {
|
impl ActionWithServer {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app, config,
|
app, config,
|
||||||
value::{PrimitiveValue, VarName},
|
value::{PrimVal, VarName},
|
||||||
};
|
};
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use app::DaemonCommand;
|
use app::DaemonCommand;
|
||||||
|
@ -197,7 +197,7 @@ impl TailVarHandler {
|
||||||
_ = handle.wait() => break,
|
_ = handle.wait() => break,
|
||||||
_ = cancellation_token.cancelled() => break,
|
_ = cancellation_token.cancelled() => break,
|
||||||
Ok(Some(line)) = stdout_lines.next_line() => {
|
Ok(Some(line)) = stdout_lines.next_line() => {
|
||||||
let new_value = PrimitiveValue::from_string(line.to_owned());
|
let new_value = PrimVal::from_string(line.to_owned());
|
||||||
evt_send.send(DaemonCommand::UpdateVars(vec![(var.name.to_owned(), new_value)]))?;
|
evt_send.send(DaemonCommand::UpdateVars(vec![(var.name.to_owned(), new_value)]))?;
|
||||||
}
|
}
|
||||||
else => break,
|
else => break,
|
||||||
|
|
|
@ -9,45 +9,45 @@ use super::super::*;
|
||||||
/// This can be a primitive String that contains any amount of variable
|
/// This can be a primitive String that contains any amount of variable
|
||||||
/// references, as would be generated by the string "foo {{var}} bar".
|
/// references, as would be generated by the string "foo {{var}} bar".
|
||||||
#[derive(Serialize, Deserialize, Clone, PartialEq, derive_more::Into, derive_more::From, Default)]
|
#[derive(Serialize, Deserialize, Clone, PartialEq, derive_more::Into, derive_more::From, Default)]
|
||||||
pub struct AttrValue(Vec<AttrValueElement>);
|
pub struct AttrVal(Vec<AttrValElement>);
|
||||||
|
|
||||||
impl fmt::Display for AttrValue {
|
impl fmt::Display for AttrVal {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.iter().map(|x| format!("{}", x)).join(""))
|
write!(f, "{}", self.iter().map(|x| format!("{}", x)).join(""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for AttrValue {
|
impl fmt::Debug for AttrVal {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "AttrValue({:?})", self.0)
|
write!(f, "AttrValue({:?})", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoIterator for AttrValue {
|
impl IntoIterator for AttrVal {
|
||||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
type Item = AttrValueElement;
|
type Item = AttrValElement;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.0.into_iter()
|
self.0.into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator<AttrValueElement> for AttrValue {
|
impl FromIterator<AttrValElement> for AttrVal {
|
||||||
fn from_iter<T: IntoIterator<Item = AttrValueElement>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = AttrValElement>>(iter: T) -> Self {
|
||||||
AttrValue(iter.into_iter().collect())
|
AttrVal(iter.into_iter().collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttrValue {
|
impl AttrVal {
|
||||||
pub fn from_primitive<T: Into<PrimitiveValue>>(v: T) -> Self {
|
pub fn from_primitive<T: Into<PrimVal>>(v: T) -> Self {
|
||||||
AttrValue(vec![AttrValueElement::Primitive(v.into())])
|
AttrVal(vec![AttrValElement::Primitive(v.into())])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_var_ref<T: Into<VarName>>(v: T) -> Self {
|
pub fn from_var_ref<T: Into<VarName>>(v: T) -> Self {
|
||||||
AttrValue(vec![AttrValueElement::Expr(AttrValueExpr::VarRef(v.into()))])
|
AttrVal(vec![AttrValElement::Expr(AttrValExpr::VarRef(v.into()))])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> std::slice::Iter<AttrValueElement> {
|
pub fn iter(&self) -> std::slice::Iter<AttrValElement> {
|
||||||
self.0.iter()
|
self.0.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,13 +58,13 @@ impl AttrValue {
|
||||||
/// resolve partially.
|
/// resolve partially.
|
||||||
/// If a var-ref links to another var-ref, that other var-ref is used.
|
/// If a var-ref links to another var-ref, that other var-ref is used.
|
||||||
/// If a referenced variable is not found in the given hashmap, returns the var-ref unchanged.
|
/// If a referenced variable is not found in the given hashmap, returns the var-ref unchanged.
|
||||||
pub fn resolve_one_level(self, variables: &HashMap<VarName, AttrValue>) -> AttrValue {
|
pub fn resolve_one_level(self, variables: &HashMap<VarName, AttrVal>) -> AttrVal {
|
||||||
self.into_iter()
|
self.into_iter()
|
||||||
.map(|entry| match entry {
|
.map(|entry| match entry {
|
||||||
AttrValueElement::Expr(expr) => AttrValueElement::Expr(expr.map_terminals_into(|child_expr| match child_expr {
|
AttrValElement::Expr(expr) => AttrValElement::Expr(expr.map_terminals_into(|child_expr| match child_expr {
|
||||||
AttrValueExpr::VarRef(var_name) => match variables.get(&var_name) {
|
AttrValExpr::VarRef(var_name) => match variables.get(&var_name) {
|
||||||
Some(value) => AttrValueExpr::Literal(value.clone()),
|
Some(value) => AttrValExpr::Literal(value.clone()),
|
||||||
None => AttrValueExpr::VarRef(var_name),
|
None => AttrValExpr::VarRef(var_name),
|
||||||
},
|
},
|
||||||
other => other,
|
other => other,
|
||||||
})),
|
})),
|
||||||
|
@ -77,17 +77,17 @@ impl AttrValue {
|
||||||
/// resolve fully.
|
/// resolve fully.
|
||||||
/// As the variables here have to be primitive values,
|
/// As the variables here have to be primitive values,
|
||||||
/// this enforces that var-refs are not linking to other variables.
|
/// this enforces that var-refs are not linking to other variables.
|
||||||
pub fn resolve_fully(self, variables: &HashMap<VarName, PrimitiveValue>) -> Result<PrimitiveValue> {
|
pub fn resolve_fully(self, variables: &HashMap<VarName, PrimVal>) -> Result<PrimVal> {
|
||||||
self.into_iter()
|
self.into_iter()
|
||||||
.map(|element| match element {
|
.map(|element| match element {
|
||||||
AttrValueElement::Primitive(x) => Ok(x),
|
AttrValElement::Primitive(x) => Ok(x),
|
||||||
AttrValueElement::Expr(expr) => expr.eval(variables),
|
AttrValElement::Expr(expr) => expr.eval(variables),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this could be a fancy Iterator implementation, ig
|
// TODO this could be a fancy Iterator implementation, ig
|
||||||
pub fn parse_string(s: &str) -> AttrValue {
|
pub fn parse_string(s: &str) -> AttrVal {
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
|
|
||||||
let mut cur_word = "".to_owned();
|
let mut cur_word = "".to_owned();
|
||||||
|
@ -98,7 +98,7 @@ impl AttrValue {
|
||||||
if c == '}' {
|
if c == '}' {
|
||||||
curly_count -= 1;
|
curly_count -= 1;
|
||||||
if curly_count == 0 {
|
if curly_count == 0 {
|
||||||
elements.push(AttrValueElement::Expr(AttrValueExpr::parse(varref).unwrap()));
|
elements.push(AttrValElement::Expr(AttrValExpr::parse(varref).unwrap()));
|
||||||
cur_varref = None
|
cur_varref = None
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,7 +109,7 @@ impl AttrValue {
|
||||||
curly_count += 1;
|
curly_count += 1;
|
||||||
if curly_count == 2 {
|
if curly_count == 2 {
|
||||||
if !cur_word.is_empty() {
|
if !cur_word.is_empty() {
|
||||||
elements.push(AttrValueElement::primitive(std::mem::take(&mut cur_word)));
|
elements.push(AttrValElement::primitive(std::mem::take(&mut cur_word)));
|
||||||
}
|
}
|
||||||
cur_varref = Some(String::new())
|
cur_varref = Some(String::new())
|
||||||
}
|
}
|
||||||
|
@ -122,52 +122,52 @@ impl AttrValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(unfinished_varref) = cur_varref.take() {
|
if let Some(unfinished_varref) = cur_varref.take() {
|
||||||
elements.push(AttrValueElement::primitive(unfinished_varref));
|
elements.push(AttrValElement::primitive(unfinished_varref));
|
||||||
} else if !cur_word.is_empty() {
|
} else if !cur_word.is_empty() {
|
||||||
elements.push(AttrValueElement::primitive(cur_word));
|
elements.push(AttrValElement::primitive(cur_word));
|
||||||
}
|
}
|
||||||
AttrValue(elements)
|
AttrVal(elements)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum AttrValueElement {
|
pub enum AttrValElement {
|
||||||
Primitive(PrimitiveValue),
|
Primitive(PrimVal),
|
||||||
Expr(AttrValueExpr),
|
Expr(AttrValExpr),
|
||||||
}
|
}
|
||||||
impl fmt::Display for AttrValueElement {
|
impl fmt::Display for AttrValElement {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
AttrValueElement::Primitive(x) => write!(f, "{}", x),
|
AttrValElement::Primitive(x) => write!(f, "{}", x),
|
||||||
AttrValueElement::Expr(x) => write!(f, "{{{{{}}}}}", x),
|
AttrValElement::Expr(x) => write!(f, "{{{{{}}}}}", x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for AttrValueElement {
|
impl fmt::Debug for AttrValElement {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
AttrValueElement::Primitive(x) => write!(f, "Primitive({:?})", x),
|
AttrValElement::Primitive(x) => write!(f, "Primitive({:?})", x),
|
||||||
AttrValueElement::Expr(x) => write!(f, "Expr({:?})", x),
|
AttrValElement::Expr(x) => write!(f, "Expr({:?})", x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttrValueElement {
|
impl AttrValElement {
|
||||||
pub fn primitive(s: String) -> Self {
|
pub fn primitive(s: String) -> Self {
|
||||||
AttrValueElement::Primitive(PrimitiveValue::from_string(s))
|
AttrValElement::Primitive(PrimVal::from_string(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_expr(&self) -> Option<&AttrValueExpr> {
|
pub fn as_expr(&self) -> Option<&AttrValExpr> {
|
||||||
match self {
|
match self {
|
||||||
AttrValueElement::Expr(x) => Some(&x),
|
AttrValElement::Expr(x) => Some(&x),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_primitive(&self) -> Option<&PrimitiveValue> {
|
pub fn as_primitive(&self) -> Option<&PrimVal> {
|
||||||
match self {
|
match self {
|
||||||
AttrValueElement::Primitive(x) => Some(&x),
|
AttrValElement::Primitive(x) => Some(&x),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,30 +180,30 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_string_or_var_ref_list() {
|
fn test_parse_string_or_var_ref_list() {
|
||||||
let input = "{{foo}}{{bar}}b{}azb{a}z{{bat}}{}quok{{test}}";
|
let input = "{{foo}}{{bar}}b{}azb{a}z{{bat}}{}quok{{test}}";
|
||||||
let output = AttrValue::parse_string(input);
|
let output = AttrVal::parse_string(input);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
output,
|
output,
|
||||||
AttrValue(vec![
|
AttrVal(vec![
|
||||||
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("foo".to_owned()))),
|
AttrValElement::Expr(AttrValExpr::VarRef(VarName("foo".to_owned()))),
|
||||||
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("bar".to_owned()))),
|
AttrValElement::Expr(AttrValExpr::VarRef(VarName("bar".to_owned()))),
|
||||||
AttrValueElement::primitive("b{}azb{a}z".to_owned()),
|
AttrValElement::primitive("b{}azb{a}z".to_owned()),
|
||||||
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("bat".to_owned()))),
|
AttrValElement::Expr(AttrValExpr::VarRef(VarName("bat".to_owned()))),
|
||||||
AttrValueElement::primitive("{}quok".to_owned()),
|
AttrValElement::primitive("{}quok".to_owned()),
|
||||||
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("test".to_owned()))),
|
AttrValElement::Expr(AttrValExpr::VarRef(VarName("test".to_owned()))),
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_string_with_var_refs_attr_value() {
|
fn test_parse_string_with_var_refs_attr_value() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
AttrValue(
|
AttrVal(
|
||||||
vec![
|
vec![
|
||||||
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("var".to_owned()))),
|
AttrValElement::Expr(AttrValExpr::VarRef(VarName("var".to_owned()))),
|
||||||
AttrValueElement::primitive("something".to_owned())
|
AttrValElement::primitive("something".to_owned())
|
||||||
]
|
]
|
||||||
.into()
|
.into()
|
||||||
),
|
),
|
||||||
AttrValue::parse_string("{{var}}something")
|
AttrVal::parse_string("{{var}}something")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,24 +52,24 @@ impl std::fmt::Display for UnaryOp {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
|
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
|
||||||
pub enum AttrValueExpr {
|
pub enum AttrValExpr {
|
||||||
Literal(AttrValue),
|
Literal(AttrVal),
|
||||||
VarRef(VarName),
|
VarRef(VarName),
|
||||||
BinOp(Box<AttrValueExpr>, BinOp, Box<AttrValueExpr>),
|
BinOp(Box<AttrValExpr>, BinOp, Box<AttrValExpr>),
|
||||||
UnaryOp(UnaryOp, Box<AttrValueExpr>),
|
UnaryOp(UnaryOp, Box<AttrValExpr>),
|
||||||
IfElse(Box<AttrValueExpr>, Box<AttrValueExpr>, Box<AttrValueExpr>),
|
IfElse(Box<AttrValExpr>, Box<AttrValExpr>, Box<AttrValExpr>),
|
||||||
JsonAccessIndex(Box<AttrValueExpr>, Box<AttrValueExpr>),
|
JsonAccess(Box<AttrValExpr>, Box<AttrValExpr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for AttrValueExpr {
|
impl std::fmt::Display for AttrValExpr {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
AttrValueExpr::VarRef(x) => write!(f, "{}", x),
|
AttrValExpr::VarRef(x) => write!(f, "{}", x),
|
||||||
AttrValueExpr::Literal(x) => write!(f, "\"{}\"", x),
|
AttrValExpr::Literal(x) => write!(f, "\"{}\"", x),
|
||||||
AttrValueExpr::BinOp(l, op, r) => write!(f, "({} {} {})", l, op, r),
|
AttrValExpr::BinOp(l, op, r) => write!(f, "({} {} {})", l, op, r),
|
||||||
AttrValueExpr::UnaryOp(op, x) => write!(f, "{}{}", op, x),
|
AttrValExpr::UnaryOp(op, x) => write!(f, "{}{}", op, x),
|
||||||
AttrValueExpr::IfElse(a, b, c) => write!(f, "(if {} then {} else {})", a, b, c),
|
AttrValExpr::IfElse(a, b, c) => write!(f, "(if {} then {} else {})", a, b, c),
|
||||||
AttrValueExpr::JsonAccessIndex(value, index) => write!(f, "{}[{}]", value, index),
|
AttrValExpr::JsonAccess(value, index) => write!(f, "{}[{}]", value, index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,9 +79,9 @@ impl std::fmt::Display for AttrValueExpr {
|
||||||
// write!(f, "{:?}", self)
|
// write!(f, "{:?}", self)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
impl AttrValueExpr {
|
impl AttrValExpr {
|
||||||
pub fn map_terminals_into(self, f: impl Fn(Self) -> Self) -> Self {
|
pub fn map_terminals_into(self, f: impl Fn(Self) -> Self) -> Self {
|
||||||
use AttrValueExpr::*;
|
use AttrValExpr::*;
|
||||||
match self {
|
match self {
|
||||||
BinOp(box a, op, box b) => BinOp(box f(a), op, box f(b)),
|
BinOp(box a, op, box b) => BinOp(box f(a), op, box f(b)),
|
||||||
IfElse(box a, box b, box c) => IfElse(box f(a), box f(b), box f(c)),
|
IfElse(box a, box b, box c) => IfElse(box f(a), box f(b), box f(c)),
|
||||||
|
@ -90,12 +90,12 @@ impl AttrValueExpr {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// resolve variable references in the expression. Fails if a variable cannot be resolved.
|
/// resolve variable references in the expression. Fails if a variable cannot be resolved.
|
||||||
pub fn resolve_refs(self, variables: &HashMap<VarName, PrimitiveValue>) -> Result<Self> {
|
pub fn resolve_refs(self, variables: &HashMap<VarName, PrimVal>) -> Result<Self> {
|
||||||
use AttrValueExpr::*;
|
use AttrValExpr::*;
|
||||||
match self {
|
match self {
|
||||||
// Literal(x) => Ok(Literal(AttrValue::from_primitive(x.resolve_fully(&variables)?))),
|
// Literal(x) => Ok(Literal(AttrValue::from_primitive(x.resolve_fully(&variables)?))),
|
||||||
Literal(x) => Ok(Literal(x)),
|
Literal(x) => Ok(Literal(x)),
|
||||||
VarRef(ref name) => Ok(Literal(AttrValue::from_primitive(
|
VarRef(ref name) => Ok(Literal(AttrVal::from_primitive(
|
||||||
variables.get(name).with_context(|| format!("Unknown variable {} referenced in {:?}", &name, &self))?.clone(),
|
variables.get(name).with_context(|| format!("Unknown variable {} referenced in {:?}", &name, &self))?.clone(),
|
||||||
))),
|
))),
|
||||||
BinOp(box a, op, box b) => Ok(BinOp(box a.resolve_refs(variables)?, op, box b.resolve_refs(variables)?)),
|
BinOp(box a, op, box b) => Ok(BinOp(box a.resolve_refs(variables)?, op, box b.resolve_refs(variables)?)),
|
||||||
|
@ -103,12 +103,12 @@ impl AttrValueExpr {
|
||||||
IfElse(box a, box b, box c) => {
|
IfElse(box a, box b, box c) => {
|
||||||
Ok(IfElse(box a.resolve_refs(variables)?, box b.resolve_refs(variables)?, box c.resolve_refs(variables)?))
|
Ok(IfElse(box a.resolve_refs(variables)?, box b.resolve_refs(variables)?, box c.resolve_refs(variables)?))
|
||||||
}
|
}
|
||||||
JsonAccessIndex(box a, box b) => Ok(JsonAccessIndex(box a.resolve_refs(variables)?, box b.resolve_refs(variables)?)),
|
JsonAccess(box a, box b) => Ok(JsonAccess(box a.resolve_refs(variables)?, box b.resolve_refs(variables)?)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn var_refs(&self) -> Vec<&VarName> {
|
pub fn var_refs(&self) -> Vec<&VarName> {
|
||||||
use AttrValueExpr::*;
|
use AttrValExpr::*;
|
||||||
match self {
|
match self {
|
||||||
Literal(s) => s.var_refs().collect(),
|
Literal(s) => s.var_refs().collect(),
|
||||||
VarRef(name) => vec![name],
|
VarRef(name) => vec![name],
|
||||||
|
@ -124,7 +124,7 @@ impl AttrValueExpr {
|
||||||
refs.append(&mut c.var_refs());
|
refs.append(&mut c.var_refs());
|
||||||
refs
|
refs
|
||||||
}
|
}
|
||||||
JsonAccessIndex(box a, box b) => {
|
JsonAccess(box a, box b) => {
|
||||||
let mut refs = a.var_refs();
|
let mut refs = a.var_refs();
|
||||||
refs.append(&mut b.var_refs());
|
refs.append(&mut b.var_refs());
|
||||||
refs
|
refs
|
||||||
|
@ -132,60 +132,60 @@ impl AttrValueExpr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval(self, values: &HashMap<VarName, PrimitiveValue>) -> Result<PrimitiveValue> {
|
pub fn eval(self, values: &HashMap<VarName, PrimVal>) -> Result<PrimVal> {
|
||||||
match self {
|
match self {
|
||||||
AttrValueExpr::Literal(x) => x.resolve_fully(&values),
|
AttrValExpr::Literal(x) => x.resolve_fully(&values),
|
||||||
AttrValueExpr::VarRef(ref name) => values
|
AttrValExpr::VarRef(ref name) => values
|
||||||
.get(name)
|
.get(name)
|
||||||
.cloned()
|
.cloned()
|
||||||
.context(format!("Got unresolved variable {} while trying to evaluate expression {:?}", &name, &self)),
|
.context(format!("Got unresolved variable {} while trying to evaluate expression {:?}", &name, &self)),
|
||||||
AttrValueExpr::BinOp(a, op, b) => {
|
AttrValExpr::BinOp(a, op, b) => {
|
||||||
let a = a.eval(values)?;
|
let a = a.eval(values)?;
|
||||||
let b = b.eval(values)?;
|
let b = b.eval(values)?;
|
||||||
Ok(match op {
|
Ok(match op {
|
||||||
BinOp::Equals => PrimitiveValue::from(a == b),
|
BinOp::Equals => PrimVal::from(a == b),
|
||||||
BinOp::NotEquals => PrimitiveValue::from(a != b),
|
BinOp::NotEquals => PrimVal::from(a != b),
|
||||||
BinOp::And => PrimitiveValue::from(a.as_bool()? && b.as_bool()?),
|
BinOp::And => PrimVal::from(a.as_bool()? && b.as_bool()?),
|
||||||
BinOp::Or => PrimitiveValue::from(a.as_bool()? || b.as_bool()?),
|
BinOp::Or => PrimVal::from(a.as_bool()? || b.as_bool()?),
|
||||||
|
|
||||||
BinOp::Plus => PrimitiveValue::from(a.as_f64()? + b.as_f64()?),
|
BinOp::Plus => PrimVal::from(a.as_f64()? + b.as_f64()?),
|
||||||
BinOp::Minus => PrimitiveValue::from(a.as_f64()? - b.as_f64()?),
|
BinOp::Minus => PrimVal::from(a.as_f64()? - b.as_f64()?),
|
||||||
BinOp::Times => PrimitiveValue::from(a.as_f64()? * b.as_f64()?),
|
BinOp::Times => PrimVal::from(a.as_f64()? * b.as_f64()?),
|
||||||
BinOp::Div => PrimitiveValue::from(a.as_f64()? / b.as_f64()?),
|
BinOp::Div => PrimVal::from(a.as_f64()? / b.as_f64()?),
|
||||||
BinOp::Mod => PrimitiveValue::from(a.as_f64()? % b.as_f64()?),
|
BinOp::Mod => PrimVal::from(a.as_f64()? % b.as_f64()?),
|
||||||
BinOp::GT => PrimitiveValue::from(a.as_f64()? > b.as_f64()?),
|
BinOp::GT => PrimVal::from(a.as_f64()? > b.as_f64()?),
|
||||||
BinOp::LT => PrimitiveValue::from(a.as_f64()? < b.as_f64()?),
|
BinOp::LT => PrimVal::from(a.as_f64()? < b.as_f64()?),
|
||||||
BinOp::Elvis => PrimitiveValue::from(if a.0.is_empty() { b } else { a }),
|
BinOp::Elvis => PrimVal::from(if a.0.is_empty() { b } else { a }),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
AttrValueExpr::UnaryOp(op, a) => {
|
AttrValExpr::UnaryOp(op, a) => {
|
||||||
let a = a.eval(values)?;
|
let a = a.eval(values)?;
|
||||||
Ok(match op {
|
Ok(match op {
|
||||||
UnaryOp::Not => PrimitiveValue::from(!a.as_bool()?),
|
UnaryOp::Not => PrimVal::from(!a.as_bool()?),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
AttrValueExpr::IfElse(cond, yes, no) => {
|
AttrValExpr::IfElse(cond, yes, no) => {
|
||||||
if cond.eval(values)?.as_bool()? {
|
if cond.eval(values)?.as_bool()? {
|
||||||
yes.eval(values)
|
yes.eval(values)
|
||||||
} else {
|
} else {
|
||||||
no.eval(values)
|
no.eval(values)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AttrValueExpr::JsonAccessIndex(val, index) => {
|
AttrValExpr::JsonAccess(val, index) => {
|
||||||
let val = val.eval(values)?;
|
let val = val.eval(values)?;
|
||||||
let index = index.eval(values)?;
|
let index = index.eval(values)?;
|
||||||
match val.as_json_value()? {
|
match val.as_json_value()? {
|
||||||
serde_json::Value::Array(val) => {
|
serde_json::Value::Array(val) => {
|
||||||
let index = index.as_i32()?;
|
let index = index.as_i32()?;
|
||||||
let indexed_value = val.get(index as usize).unwrap_or(&serde_json::Value::Null);
|
let indexed_value = val.get(index as usize).unwrap_or(&serde_json::Value::Null);
|
||||||
Ok(PrimitiveValue::from(indexed_value))
|
Ok(PrimVal::from(indexed_value))
|
||||||
}
|
}
|
||||||
serde_json::Value::Object(val) => {
|
serde_json::Value::Object(val) => {
|
||||||
let indexed_value = val
|
let indexed_value = val
|
||||||
.get(&index.as_string()?)
|
.get(&index.as_string()?)
|
||||||
.or_else(|| val.get(&format!("{}", index.as_i32().ok()?)))
|
.or_else(|| val.get(&index.as_i32().ok()?.to_string()))
|
||||||
.unwrap_or(&serde_json::Value::Null);
|
.unwrap_or(&serde_json::Value::Null);
|
||||||
Ok(PrimitiveValue::from(indexed_value))
|
Ok(PrimVal::from(indexed_value))
|
||||||
}
|
}
|
||||||
_ => bail!("Unable to index into value {}", val),
|
_ => bail!("Unable to index into value {}", val),
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,34 +53,34 @@ fn parse_unary_op(i: &str) -> IResult<&str, UnaryOp, VerboseError<&str>> {
|
||||||
// actual tree //
|
// actual tree //
|
||||||
/////////////////
|
/////////////////
|
||||||
|
|
||||||
fn parse_factor(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
fn parse_factor(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
|
||||||
let (i, unary_op) = opt(parse_unary_op)(i)?;
|
let (i, unary_op) = opt(parse_unary_op)(i)?;
|
||||||
let (i, factor) = alt((
|
let (i, factor) = alt((
|
||||||
context("expression", ws(delimited(tag("("), parse_expr, tag(")")))),
|
context("expression", ws(delimited(tag("("), parse_expr, tag(")")))),
|
||||||
context("if-expression", ws(parse_ifelse)),
|
context("if-expression", ws(parse_ifelse)),
|
||||||
context("literal", map(ws(parse_literal), |x| AttrValueExpr::Literal(AttrValue::parse_string(x)))),
|
context("literal", map(ws(parse_literal), |x| AttrValExpr::Literal(AttrVal::parse_string(x)))),
|
||||||
context("identifier", map(ws(parse_identifier), |x| AttrValueExpr::VarRef(VarName(x.to_string())))),
|
context("identifier", map(ws(parse_identifier), |x| AttrValExpr::VarRef(VarName(x.to_string())))),
|
||||||
))(i)?;
|
))(i)?;
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
match unary_op {
|
match unary_op {
|
||||||
Some(op) => AttrValueExpr::UnaryOp(op, box factor),
|
Some(op) => AttrValExpr::UnaryOp(op, box factor),
|
||||||
None => factor,
|
None => factor,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_object_index(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
fn parse_object_index(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
|
||||||
let (i, initial) = parse_factor(i)?;
|
let (i, initial) = parse_factor(i)?;
|
||||||
let (i, remainder) = many0(alt((
|
let (i, remainder) = many0(alt((
|
||||||
delimited(tag("["), ws(parse_expr), tag("]")),
|
delimited(tag("["), ws(parse_expr), tag("]")),
|
||||||
map(preceded(tag("."), parse_identifier), |x| AttrValueExpr::Literal(AttrValue::from_primitive(x))),
|
map(preceded(tag("."), parse_identifier), |x| AttrValExpr::Literal(AttrVal::from_primitive(x))),
|
||||||
)))(i)?;
|
)))(i)?;
|
||||||
let indexes = remainder.into_iter().fold(initial, |acc, index| AttrValueExpr::JsonAccessIndex(box acc, box index));
|
let indexes = remainder.into_iter().fold(initial, |acc, index| AttrValExpr::JsonAccess(box acc, box index));
|
||||||
Ok((i, indexes))
|
Ok((i, indexes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_term3(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
fn parse_term3(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
|
||||||
let (i, initial) = parse_object_index(i)?;
|
let (i, initial) = parse_object_index(i)?;
|
||||||
let (i, remainder) = many0(alt((
|
let (i, remainder) = many0(alt((
|
||||||
map(preceded(tag("*"), parse_object_index), |x| (BinOp::Times, x)),
|
map(preceded(tag("*"), parse_object_index), |x| (BinOp::Times, x)),
|
||||||
|
@ -88,23 +88,23 @@ fn parse_term3(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
||||||
map(preceded(tag("%"), parse_object_index), |x| (BinOp::Mod, x)),
|
map(preceded(tag("%"), parse_object_index), |x| (BinOp::Mod, x)),
|
||||||
)))(i)?;
|
)))(i)?;
|
||||||
|
|
||||||
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValExpr::BinOp(box acc, op, box expr));
|
||||||
|
|
||||||
Ok((i, exprs))
|
Ok((i, exprs))
|
||||||
}
|
}
|
||||||
fn parse_term2(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
fn parse_term2(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
|
||||||
let (i, initial) = parse_term3(i)?;
|
let (i, initial) = parse_term3(i)?;
|
||||||
let (i, remainder) = many0(alt((
|
let (i, remainder) = many0(alt((
|
||||||
map(preceded(tag("+"), parse_term3), |x| (BinOp::Plus, x)),
|
map(preceded(tag("+"), parse_term3), |x| (BinOp::Plus, x)),
|
||||||
map(preceded(tag("-"), parse_term3), |x| (BinOp::Minus, x)),
|
map(preceded(tag("-"), parse_term3), |x| (BinOp::Minus, x)),
|
||||||
)))(i)?;
|
)))(i)?;
|
||||||
|
|
||||||
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValExpr::BinOp(box acc, op, box expr));
|
||||||
|
|
||||||
Ok((i, exprs))
|
Ok((i, exprs))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_term1(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
fn parse_term1(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
|
||||||
let (i, initial) = parse_term2(i)?;
|
let (i, initial) = parse_term2(i)?;
|
||||||
let (i, remainder) = many0(alt((
|
let (i, remainder) = many0(alt((
|
||||||
map(preceded(tag("=="), parse_term2), |x| (BinOp::Equals, x)),
|
map(preceded(tag("=="), parse_term2), |x| (BinOp::Equals, x)),
|
||||||
|
@ -113,11 +113,11 @@ fn parse_term1(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
||||||
map(preceded(tag("<"), parse_term2), |x| (BinOp::LT, x)),
|
map(preceded(tag("<"), parse_term2), |x| (BinOp::LT, x)),
|
||||||
)))(i)?;
|
)))(i)?;
|
||||||
|
|
||||||
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValExpr::BinOp(box acc, op, box expr));
|
||||||
|
|
||||||
Ok((i, exprs))
|
Ok((i, exprs))
|
||||||
}
|
}
|
||||||
pub fn parse_expr(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
pub fn parse_expr(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
|
||||||
let (i, initial) = parse_term1(i)?;
|
let (i, initial) = parse_term1(i)?;
|
||||||
let (i, remainder) = many0(alt((
|
let (i, remainder) = many0(alt((
|
||||||
map(preceded(tag("&&"), parse_term1), |x| (BinOp::And, x)),
|
map(preceded(tag("&&"), parse_term1), |x| (BinOp::And, x)),
|
||||||
|
@ -125,22 +125,22 @@ pub fn parse_expr(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
||||||
map(preceded(tag("?:"), parse_term1), |x| (BinOp::Elvis, x)),
|
map(preceded(tag("?:"), parse_term1), |x| (BinOp::Elvis, x)),
|
||||||
)))(i)?;
|
)))(i)?;
|
||||||
|
|
||||||
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValExpr::BinOp(box acc, op, box expr));
|
||||||
|
|
||||||
Ok((i, exprs))
|
Ok((i, exprs))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ifelse(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
fn parse_ifelse(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
|
||||||
let (i, _) = tag("if")(i)?;
|
let (i, _) = tag("if")(i)?;
|
||||||
let (i, a) = context("condition", ws(parse_expr))(i)?;
|
let (i, a) = context("condition", ws(parse_expr))(i)?;
|
||||||
let (i, _) = tag("then")(i)?;
|
let (i, _) = tag("then")(i)?;
|
||||||
let (i, b) = context("true-case", ws(parse_expr))(i)?;
|
let (i, b) = context("true-case", ws(parse_expr))(i)?;
|
||||||
let (i, _) = tag("else")(i)?;
|
let (i, _) = tag("else")(i)?;
|
||||||
let (i, c) = context("false-case", ws(parse_expr))(i)?;
|
let (i, c) = context("false-case", ws(parse_expr))(i)?;
|
||||||
Ok((i, AttrValueExpr::IfElse(box a, box b, box c)))
|
Ok((i, AttrValExpr::IfElse(box a, box b, box c)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse<'a>(i: &'a str) -> IResult<&'a str, AttrValueExpr, VerboseError<&'a str>> {
|
pub fn parse<'a>(i: &'a str) -> IResult<&'a str, AttrValExpr, VerboseError<&'a str>> {
|
||||||
complete(parse_expr)(i)
|
complete(parse_expr)(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,64 +150,64 @@ mod test {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parser() {
|
fn test_parser() {
|
||||||
assert_eq!(AttrValueExpr::Literal(AttrValue::from_primitive("12")), AttrValueExpr::parse("12").unwrap());
|
assert_eq!(AttrValExpr::Literal(AttrVal::from_primitive("12")), AttrValExpr::parse("12").unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
AttrValueExpr::UnaryOp(UnaryOp::Not, box AttrValueExpr::Literal(AttrValue::from_primitive("false"))),
|
AttrValExpr::UnaryOp(UnaryOp::Not, box AttrValExpr::Literal(AttrVal::from_primitive("false"))),
|
||||||
AttrValueExpr::parse("!false").unwrap()
|
AttrValExpr::parse("!false").unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
AttrValueExpr::BinOp(
|
AttrValExpr::BinOp(
|
||||||
box AttrValueExpr::Literal(AttrValue::from_primitive("12")),
|
box AttrValExpr::Literal(AttrVal::from_primitive("12")),
|
||||||
BinOp::Plus,
|
BinOp::Plus,
|
||||||
box AttrValueExpr::Literal(AttrValue::from_primitive("2"))
|
box AttrValExpr::Literal(AttrVal::from_primitive("2"))
|
||||||
),
|
),
|
||||||
AttrValueExpr::parse("12 + 2").unwrap()
|
AttrValExpr::parse("12 + 2").unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
AttrValueExpr::UnaryOp(
|
AttrValExpr::UnaryOp(
|
||||||
UnaryOp::Not,
|
UnaryOp::Not,
|
||||||
box AttrValueExpr::BinOp(
|
box AttrValExpr::BinOp(
|
||||||
box AttrValueExpr::Literal(AttrValue::from_primitive("1")),
|
box AttrValExpr::Literal(AttrVal::from_primitive("1")),
|
||||||
BinOp::Equals,
|
BinOp::Equals,
|
||||||
box AttrValueExpr::Literal(AttrValue::from_primitive("2"))
|
box AttrValExpr::Literal(AttrVal::from_primitive("2"))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
AttrValueExpr::parse("!(1 == 2)").unwrap()
|
AttrValExpr::parse("!(1 == 2)").unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
AttrValueExpr::IfElse(
|
AttrValExpr::IfElse(
|
||||||
box AttrValueExpr::VarRef(VarName("a".to_string())),
|
box AttrValExpr::VarRef(VarName("a".to_string())),
|
||||||
box AttrValueExpr::VarRef(VarName("b".to_string())),
|
box AttrValExpr::VarRef(VarName("b".to_string())),
|
||||||
box AttrValueExpr::VarRef(VarName("c".to_string())),
|
box AttrValExpr::VarRef(VarName("c".to_string())),
|
||||||
),
|
),
|
||||||
AttrValueExpr::parse("if a then b else c").unwrap()
|
AttrValExpr::parse("if a then b else c").unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
AttrValueExpr::JsonAccessIndex(
|
AttrValExpr::JsonAccess(
|
||||||
box AttrValueExpr::VarRef(VarName("array".to_string())),
|
box AttrValExpr::VarRef(VarName("array".to_string())),
|
||||||
box AttrValueExpr::BinOp(
|
box AttrValExpr::BinOp(
|
||||||
box AttrValueExpr::Literal(AttrValue::from_primitive("1")),
|
box AttrValExpr::Literal(AttrVal::from_primitive("1")),
|
||||||
BinOp::Plus,
|
BinOp::Plus,
|
||||||
box AttrValueExpr::Literal(AttrValue::from_primitive("2"))
|
box AttrValExpr::Literal(AttrVal::from_primitive("2"))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
AttrValueExpr::parse(r#"(array)[1+2]"#).unwrap()
|
AttrValExpr::parse(r#"(array)[1+2]"#).unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
AttrValueExpr::JsonAccessIndex(
|
AttrValExpr::JsonAccess(
|
||||||
box AttrValueExpr::JsonAccessIndex(
|
box AttrValExpr::JsonAccess(
|
||||||
box AttrValueExpr::VarRef(VarName("object".to_string())),
|
box AttrValExpr::VarRef(VarName("object".to_string())),
|
||||||
box AttrValueExpr::Literal(AttrValue::from_primitive("field".to_string())),
|
box AttrValExpr::Literal(AttrVal::from_primitive("field".to_string())),
|
||||||
),
|
),
|
||||||
box AttrValueExpr::Literal(AttrValue::from_primitive("field2".to_string())),
|
box AttrValExpr::Literal(AttrVal::from_primitive("field2".to_string())),
|
||||||
),
|
),
|
||||||
AttrValueExpr::parse(r#"object.field.field2"#).unwrap()
|
AttrValExpr::parse(r#"object.field.field2"#).unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_complex() {
|
fn test_complex() {
|
||||||
let parsed =
|
let parsed =
|
||||||
AttrValueExpr::parse(r#"if hi > 12 + 2 * 2 && 12 == 15 then "foo" else if !true then 'hi' else "{{bruh}}""#).unwrap();
|
AttrValExpr::parse(r#"if hi > 12 + 2 * 2 && 12 == 15 then "foo" else if !true then 'hi' else "{{bruh}}""#).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
r#"(if ((hi > ("12" + ("2" * "2"))) && ("12" == "15")) then "foo" else (if !"true" then "hi" else "{{bruh}}"))"#,
|
r#"(if ((hi > ("12" + ("2" * "2"))) && ("12" == "15")) then "foo" else (if !"true" then "hi" else "{{bruh}}"))"#,
|
||||||
|
|
|
@ -6,21 +6,21 @@ use std::{convert::TryFrom, fmt, iter::FromIterator};
|
||||||
use crate::impl_try_from;
|
use crate::impl_try_from;
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize, derive_more::From, Default)]
|
#[derive(Clone, Deserialize, Serialize, derive_more::From, Default)]
|
||||||
pub struct PrimitiveValue(pub String);
|
pub struct PrimVal(pub String);
|
||||||
|
|
||||||
impl fmt::Display for PrimitiveValue {
|
impl fmt::Display for PrimVal {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self.0)
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl fmt::Debug for PrimitiveValue {
|
impl fmt::Debug for PrimVal {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "\"{}\"", self.0)
|
write!(f, "\"{}\"", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Manually implement equality, to allow for values in different formats (i.e. "1" and "1.0") to still be considered as equal.
|
/// Manually implement equality, to allow for values in different formats (i.e. "1" and "1.0") to still be considered as equal.
|
||||||
impl std::cmp::PartialEq<Self> for PrimitiveValue {
|
impl std::cmp::PartialEq<Self> for PrimVal {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
if let (Ok(a), Ok(b)) = (self.as_f64(), other.as_f64()) {
|
if let (Ok(a), Ok(b)) = (self.as_f64(), other.as_f64()) {
|
||||||
a == b
|
a == b
|
||||||
|
@ -30,56 +30,56 @@ impl std::cmp::PartialEq<Self> for PrimitiveValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator<PrimitiveValue> for PrimitiveValue {
|
impl FromIterator<PrimVal> for PrimVal {
|
||||||
fn from_iter<T: IntoIterator<Item = PrimitiveValue>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = PrimVal>>(iter: T) -> Self {
|
||||||
PrimitiveValue(iter.into_iter().join(""))
|
PrimVal(iter.into_iter().join(""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::str::FromStr for PrimitiveValue {
|
impl std::str::FromStr for PrimVal {
|
||||||
type Err = anyhow::Error;
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
/// parses the value, trying to turn it into a number and a boolean first,
|
/// parses the value, trying to turn it into a number and a boolean first,
|
||||||
/// before deciding that it is a string.
|
/// before deciding that it is a string.
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
Ok(PrimitiveValue::from_string(s.to_string()))
|
Ok(PrimVal::from_string(s.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_try_from!(PrimitiveValue {
|
impl_try_from!(PrimVal {
|
||||||
for String => |x| x.as_string();
|
for String => |x| x.as_string();
|
||||||
for f64 => |x| x.as_f64();
|
for f64 => |x| x.as_f64();
|
||||||
for bool => |x| x.as_bool();
|
for bool => |x| x.as_bool();
|
||||||
for Vec<String> => |x| x.as_vec();
|
for Vec<String> => |x| x.as_vec();
|
||||||
});
|
});
|
||||||
|
|
||||||
impl From<bool> for PrimitiveValue {
|
impl From<bool> for PrimVal {
|
||||||
fn from(x: bool) -> Self {
|
fn from(x: bool) -> Self {
|
||||||
PrimitiveValue(x.to_string())
|
PrimVal(x.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<i32> for PrimitiveValue {
|
impl From<i32> for PrimVal {
|
||||||
fn from(s: i32) -> Self {
|
fn from(s: i32) -> Self {
|
||||||
PrimitiveValue(s.to_string())
|
PrimVal(s.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<f64> for PrimitiveValue {
|
impl From<f64> for PrimVal {
|
||||||
fn from(s: f64) -> Self {
|
fn from(s: f64) -> Self {
|
||||||
PrimitiveValue(s.to_string())
|
PrimVal(s.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for PrimitiveValue {
|
impl From<&str> for PrimVal {
|
||||||
fn from(s: &str) -> Self {
|
fn from(s: &str) -> Self {
|
||||||
PrimitiveValue(s.to_string())
|
PrimVal(s.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&serde_json::Value> for PrimitiveValue {
|
impl From<&serde_json::Value> for PrimVal {
|
||||||
fn from(v: &serde_json::Value) -> Self {
|
fn from(v: &serde_json::Value) -> Self {
|
||||||
PrimitiveValue(
|
PrimVal(
|
||||||
v.as_str()
|
v.as_str()
|
||||||
.map(|x| x.to_string())
|
.map(|x| x.to_string())
|
||||||
.or_else(|| serde_json::to_string(v).ok())
|
.or_else(|| serde_json::to_string(v).ok())
|
||||||
|
@ -88,9 +88,9 @@ impl From<&serde_json::Value> for PrimitiveValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrimitiveValue {
|
impl PrimVal {
|
||||||
pub fn from_string(s: String) -> Self {
|
pub fn from_string(s: String) -> Self {
|
||||||
PrimitiveValue(s)
|
PrimVal(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_inner(self) -> String {
|
pub fn into_inner(self) -> String {
|
||||||
|
|
|
@ -154,7 +154,7 @@ macro_rules! resolve_block {
|
||||||
};
|
};
|
||||||
|
|
||||||
(@get_value $args:ident, $name:expr, = $default:expr) => {
|
(@get_value $args:ident, $name:expr, = $default:expr) => {
|
||||||
$args.widget.get_attr($name).cloned().unwrap_or(AttrValue::from_primitive($default))
|
$args.widget.get_attr($name).cloned().unwrap_or(AttrVal::from_primitive($default))
|
||||||
};
|
};
|
||||||
|
|
||||||
(@get_value $args:ident, $name:expr,) => {
|
(@get_value $args:ident, $name:expr,) => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::{run_command, BuilderArgs};
|
use super::{run_command, BuilderArgs};
|
||||||
use crate::{config, eww_state, resolve_block, value::AttrValue, widgets::widget_node};
|
use crate::{config, eww_state, resolve_block, value::AttrVal, widgets::widget_node};
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use gtk::{prelude::*, ImageExt};
|
use gtk::{prelude::*, ImageExt};
|
||||||
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
WindowName,
|
WindowName,
|
||||||
},
|
},
|
||||||
eww_state::EwwState,
|
eww_state::EwwState,
|
||||||
value::{AttrName, AttrValue, VarName},
|
value::{AttrName, AttrVal, VarName},
|
||||||
};
|
};
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use dyn_clone;
|
use dyn_clone;
|
||||||
|
@ -62,11 +62,11 @@ pub struct Generic {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub text_pos: Option<TextPos>,
|
pub text_pos: Option<TextPos>,
|
||||||
pub children: Vec<Box<dyn WidgetNode>>,
|
pub children: Vec<Box<dyn WidgetNode>>,
|
||||||
pub attrs: HashMap<AttrName, AttrValue>,
|
pub attrs: HashMap<AttrName, AttrVal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Generic {
|
impl Generic {
|
||||||
pub fn get_attr(&self, key: &str) -> Result<&AttrValue> {
|
pub fn get_attr(&self, key: &str) -> Result<&AttrVal> {
|
||||||
self.attrs.get(key).context(format!("attribute '{}' missing from use of '{}'", key, &self.name))
|
self.attrs.get(key).context(format!("attribute '{}' missing from use of '{}'", key, &self.name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ impl WidgetNode for Generic {
|
||||||
|
|
||||||
pub fn generate_generic_widget_node(
|
pub fn generate_generic_widget_node(
|
||||||
defs: &HashMap<String, WidgetDefinition>,
|
defs: &HashMap<String, WidgetDefinition>,
|
||||||
local_env: &HashMap<VarName, AttrValue>,
|
local_env: &HashMap<VarName, AttrVal>,
|
||||||
w: WidgetUse,
|
w: WidgetUse,
|
||||||
) -> Result<Box<dyn WidgetNode>> {
|
) -> Result<Box<dyn WidgetNode>> {
|
||||||
if let Some(def) = defs.get(&w.name) {
|
if let Some(def) = defs.get(&w.name) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue