there was an attempt at variable intrepolation support

This commit is contained in:
elkowar 2020-09-19 17:10:52 +02:00
parent 3cbd81219b
commit f173ec04e3
4 changed files with 100 additions and 855 deletions

815
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -11,8 +11,10 @@ gtk = { version = "0.9", features = [ "v3_16" ] }
gdk = { version = "", features = ["v3_16"] } gdk = { version = "", features = ["v3_16"] }
gio = { version = "", features = ["v2_44"] } gio = { version = "", features = ["v2_44"] }
regex = "1"
hocon = { version = "0.3", features = [ "serde-support" ]}
hocon = { version = "0.3", default-features = false, features = [ "serde-support" ]}
try_match = "0.2.2" try_match = "0.2.2"
@ -20,8 +22,3 @@ anyhow = "1.0"
#thiserror = "1.0" #thiserror = "1.0"
[target.x86_64-unknown-linux-gnu]
rustflags = [
"-C", "link-arg=-fuse-ld=lld",
]

View file

@ -1,11 +1,14 @@
use anyhow::*; use anyhow::*;
use hocon::*; use hocon::*;
use hocon_ext::HoconExt; use hocon_ext::HoconExt;
use std::collections::HashMap; use std::{collections::HashMap, convert::TryFrom};
use try_match::try_match; use try_match::try_match;
pub mod hocon_ext; pub mod hocon_ext;
#[derive(Debug, PartialEq, Eq)]
pub struct AttrValue(pub String);
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct WidgetDefinition { pub struct WidgetDefinition {
pub name: String, pub name: String,
@ -22,8 +25,7 @@ pub enum ElementUse {
pub struct WidgetUse { pub struct WidgetUse {
pub name: String, pub name: String,
pub children: Vec<ElementUse>, pub children: Vec<ElementUse>,
pub num_attrs: HashMap<String, f64>, pub attrs: HashMap<String, AttrValue>,
pub str_attrs: HashMap<String, String>,
} }
impl WidgetUse { impl WidgetUse {
@ -31,8 +33,7 @@ impl WidgetUse {
WidgetUse { WidgetUse {
name, name,
children, children,
num_attrs: HashMap::new(), attrs: HashMap::new(),
str_attrs: HashMap::new(),
} }
} }
} }
@ -85,25 +86,18 @@ pub fn parse_widget_use(data: HashMap<String, Hocon>) -> Result<WidgetUse> {
)), )),
}?; }?;
let str_attrs: HashMap<String, String> = widget_config let attrs: HashMap<String, AttrValue> = widget_config
.into_iter() .into_iter()
.filter_map(|(key, value)| { .filter_map(|(key, value)| {
Some(( Some((
key.clone(), key.clone(),
try_match!(Hocon::String(x) = value).ok()?.clone(), match value {
)) Hocon::String(s) => AttrValue(s.to_string()),
}) Hocon::Integer(n) => AttrValue(format!("{}", n)),
.collect(); Hocon::Real(n) => AttrValue(format!("{}", n)),
Hocon::Boolean(b) => AttrValue(format!("{}", b)),
let num_attrs: HashMap<String, f64> = widget_config _ => return None,
.iter() },
.filter_map(|(key, value)| {
Some((
key.to_string(),
try_match!(Hocon::Integer(x) = value)
.map(|&x| x as f64)
.or_else(|_| try_match!(Hocon::Real(x) = value).map(|&x| x as f64))
.ok()?,
)) ))
}) })
.collect(); .collect();
@ -111,8 +105,7 @@ pub fn parse_widget_use(data: HashMap<String, Hocon>) -> Result<WidgetUse> {
Ok(WidgetUse { Ok(WidgetUse {
name: widget_name.to_string(), name: widget_name.to_string(),
children, children,
str_attrs, attrs,
num_attrs,
}) })
} }
@ -150,6 +143,7 @@ mod test {
name: "example_widget".to_string(), name: "example_widget".to_string(),
structure: ElementUse::Widget(WidgetUse { structure: ElementUse::Widget(WidgetUse {
name: "layout_horizontal".to_string(), name: "layout_horizontal".to_string(),
attrs: HashMap::new(),
children: vec![ children: vec![
ElementUse::Widget(WidgetUse::new( ElementUse::Widget(WidgetUse::new(
"text".to_string(), "text".to_string(),

View file

@ -1,11 +1,14 @@
#![feature(try_blocks)]
extern crate gio; extern crate gio;
extern crate gtk; extern crate gtk;
use anyhow::*; use anyhow::{self, Context, Result};
use gdk::*; use gdk::*;
use gio::prelude::*; use gio::prelude::*;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{Adjustment, Application, ApplicationWindow, Button, Scale}; use gtk::{Adjustment, Application, ApplicationWindow, Button, Scale};
use regex::Regex;
use std::{collections::HashMap, str::FromStr};
pub mod config; pub mod config;
pub mod widgets; pub mod widgets;
@ -20,6 +23,7 @@ fn main() -> Result<()> {
window.set_wmclass("noswallow", "noswallow"); window.set_wmclass("noswallow", "noswallow");
window.set_type_hint(gdk::WindowTypeHint::Dock); window.set_type_hint(gdk::WindowTypeHint::Dock);
window.set_position(gtk::WindowPosition::Center); window.set_position(gtk::WindowPosition::Center);
window.set_keep_above(true);
let element = config::parse_element_use( let element = config::parse_element_use(
config::parse_hocon( config::parse_hocon(
@ -37,7 +41,10 @@ fn main() -> Result<()> {
.unwrap(), .unwrap(),
) )
.unwrap(); .unwrap();
window.add(&element_to_gtk_widget(&element).unwrap());
let widget_state = WidgetState(HashMap::new());
window.add(&element_to_gtk_widget(&widget_state, &element).unwrap());
window.show_all(); window.show_all();
}); });
@ -46,16 +53,21 @@ fn main() -> Result<()> {
Ok(()) Ok(())
} }
fn element_to_gtk_widget(element: &config::ElementUse) -> Option<gtk::Widget> { fn element_to_gtk_widget(
widget_state: &WidgetState,
element: &config::ElementUse,
) -> Option<gtk::Widget> {
match element { match element {
config::ElementUse::Text(text) => Some(gtk::Label::new(Some(&text)).upcast()), config::ElementUse::Text(text) => Some(gtk::Label::new(Some(&text)).upcast()),
config::ElementUse::Widget(widget) => { config::ElementUse::Widget(widget) => widget_use_to_gtk_container(widget_state, &widget)
widget_use_to_gtk_container(&widget).or(widget_use_to_gtk_widget(&widget)) .or(widget_use_to_gtk_widget(widget_state, &widget)),
}
} }
} }
fn widget_use_to_gtk_container(widget: &config::WidgetUse) -> Option<gtk::Widget> { fn widget_use_to_gtk_container(
widget_state: &WidgetState,
widget: &config::WidgetUse,
) -> Option<gtk::Widget> {
let container_widget: gtk::Container = match widget.name.as_str() { let container_widget: gtk::Container = match widget.name.as_str() {
"layout_horizontal" => gtk::Box::new(gtk::Orientation::Horizontal, 0).upcast(), "layout_horizontal" => gtk::Box::new(gtk::Orientation::Horizontal, 0).upcast(),
"button" => gtk::Button::new().upcast(), "button" => gtk::Button::new().upcast(),
@ -63,20 +75,73 @@ fn widget_use_to_gtk_container(widget: &config::WidgetUse) -> Option<gtk::Widget
}; };
for child in &widget.children { for child in &widget.children {
container_widget.add(&element_to_gtk_widget(child)?); container_widget.add(&element_to_gtk_widget(widget_state, child)?);
} }
Some(container_widget.upcast()) Some(container_widget.upcast())
} }
fn widget_use_to_gtk_widget(widget: &config::WidgetUse) -> Option<gtk::Widget> { fn widget_use_to_gtk_widget(
widget_state: &WidgetState,
widget: &config::WidgetUse,
) -> Option<gtk::Widget> {
let new_widget: gtk::Widget = match widget.name.as_str() { let new_widget: gtk::Widget = match widget.name.as_str() {
"slider" => gtk::Scale::new( "slider" => {
let slider_value: f64 = widget_state.resolve(widget.attrs.get("value")?)?;
gtk::Scale::new(
gtk::Orientation::Horizontal, gtk::Orientation::Horizontal,
Some(&gtk::Adjustment::new(50.0, 0.0, 100.0, 1.0, 1.0, 1.0)), Some(&gtk::Adjustment::new(
slider_value,
0.0,
100.0,
1.0,
1.0,
1.0,
)),
) )
.upcast(), .upcast()
}
_ => return None, _ => return None,
}; };
Some(new_widget) Some(new_widget)
} }
struct WidgetState(HashMap<String, config::AttrValue>);
impl WidgetState {
pub fn resolve<T>(&self, value: &config::AttrValue) -> Option<String>
where
T: FromStr,
{
let var_pattern: Regex = Regex::new(r"\$\$\{(.*)\}").unwrap();
let config::AttrValue(value) = value;
let mut missing_var: Option<String> = None;
var_pattern.replace_all(value, |caps: &regex::Captures| {
self.lookup_full::<T>(&caps[1]).unwrap_or_else(|| {
missing_var = Some(caps[1].to_string());
"missing".to_string()
})
});
// TODO REEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEe
unimplemented!();
}
pub fn lookup_full<T>(&self, key: &str) -> Option<String>
where
T: FromStr,
{
self.resolve::<T>(self.0.get(key)?)
}
}
// macro_rules! build {
// ($var_name:ident = $value:expr ; $code:block) => {{
// let mut $var_name = $value;
// $code;
// $var_name
// }};
// }