Cleanup resolve! macro
This commit is contained in:
parent
60c6f1b28f
commit
8ed820787a
5 changed files with 137 additions and 114 deletions
|
@ -45,7 +45,7 @@ impl ElementUse {
|
||||||
match hocon {
|
match hocon {
|
||||||
Hocon::String(s) => Ok(ElementUse::Text(s)),
|
Hocon::String(s) => Ok(ElementUse::Text(s)),
|
||||||
Hocon::Hash(hash) => WidgetUse::parse_hocon_hash(hash).map(ElementUse::Widget),
|
Hocon::Hash(hash) => WidgetUse::parse_hocon_hash(hash).map(ElementUse::Widget),
|
||||||
_ => Err(anyhow!("{:?} is not a valid element", hocon)),
|
_ => Err(anyhow!("'{:?}' is not a valid element", hocon)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ impl WidgetUse {
|
||||||
.collect::<Result<Vec<_>>>(),
|
.collect::<Result<Vec<_>>>(),
|
||||||
None => Ok(Vec::new()),
|
None => Ok(Vec::new()),
|
||||||
_ => Err(anyhow!(
|
_ => Err(anyhow!(
|
||||||
"children must be either a list of elements or a string, but was {:?}"
|
"children must be either a list of elements or a string, but was '{:?}'"
|
||||||
)),
|
)),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ impl WidgetUse {
|
||||||
|
|
||||||
pub fn get_attr(&self, key: &str) -> Result<&AttrValue> {
|
pub fn get_attr(&self, key: &str) -> Result<&AttrValue> {
|
||||||
self.attrs.get(key).context(format!(
|
self.attrs.get(key).context(format!(
|
||||||
"attribute {} missing from widgetuse of {}",
|
"attribute '{}' missing from widgetuse of '{}'",
|
||||||
key, &self.name
|
key, &self.name
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ impl EwwState {
|
||||||
value: &AttrValue,
|
value: &AttrValue,
|
||||||
set_value: F,
|
set_value: F,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
dbg!("resolve: ", value);
|
|
||||||
match value {
|
match value {
|
||||||
AttrValue::VarRef(name) => {
|
AttrValue::VarRef(name) => {
|
||||||
if let Some(value) = self.state.get(name).cloned() {
|
if let Some(value) = self.state.get(name).cloned() {
|
||||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -1,3 +1,4 @@
|
||||||
|
#![feature(trace_macros)]
|
||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
extern crate gio;
|
extern crate gio;
|
||||||
extern crate gtk;
|
extern crate gtk;
|
||||||
|
@ -14,9 +15,8 @@ pub mod eww_state;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
pub mod widgets;
|
pub mod widgets;
|
||||||
|
|
||||||
use config::element;
|
|
||||||
use eww_state::*;
|
use eww_state::*;
|
||||||
use value::{AttrValue, PrimitiveValue};
|
use value::PrimitiveValue;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! build {
|
macro_rules! build {
|
||||||
|
@ -82,7 +82,6 @@ fn main() {
|
||||||
|
|
||||||
fn try_main() -> Result<()> {
|
fn try_main() -> Result<()> {
|
||||||
let eww_config = config::EwwConfig::from_hocon(&config::parse_hocon(EXAMPLE_CONFIG)?)?;
|
let eww_config = config::EwwConfig::from_hocon(&config::parse_hocon(EXAMPLE_CONFIG)?)?;
|
||||||
dbg!(&eww_config);
|
|
||||||
|
|
||||||
let application = Application::new(Some("de.elkowar.eww"), gio::ApplicationFlags::FLAGS_NONE)
|
let application = Application::new(Some("de.elkowar.eww"), gio::ApplicationFlags::FLAGS_NONE)
|
||||||
.expect("failed to initialize GTK application ");
|
.expect("failed to initialize GTK application ");
|
||||||
|
@ -90,6 +89,7 @@ fn try_main() -> Result<()> {
|
||||||
let window_def = eww_config.get_windows()["main_window"].clone();
|
let window_def = eww_config.get_windows()["main_window"].clone();
|
||||||
|
|
||||||
application.connect_activate(move |app| {
|
application.connect_activate(move |app| {
|
||||||
|
let result: Result<()> = try {
|
||||||
let app_window = ApplicationWindow::new(app);
|
let app_window = ApplicationWindow::new(app);
|
||||||
app_window.set_title("Eww");
|
app_window.set_title("Eww");
|
||||||
app_window.set_wmclass("noswallow", "noswallow");
|
app_window.set_wmclass("noswallow", "noswallow");
|
||||||
|
@ -116,15 +116,12 @@ fn try_main() -> Result<()> {
|
||||||
let mut eww_state = EwwState::from_default_vars(eww_config.get_default_vars().clone());
|
let mut eww_state = EwwState::from_default_vars(eww_config.get_default_vars().clone());
|
||||||
let empty_local_state = HashMap::new();
|
let empty_local_state = HashMap::new();
|
||||||
|
|
||||||
app_window.add(
|
app_window.add(&widgets::element_to_gtk_thing(
|
||||||
&widgets::element_to_gtk_thing(
|
|
||||||
&eww_config.get_widgets(),
|
&eww_config.get_widgets(),
|
||||||
&mut eww_state,
|
&mut eww_state,
|
||||||
&empty_local_state,
|
&empty_local_state,
|
||||||
&window_def.widget,
|
&window_def.widget,
|
||||||
)
|
)?);
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
app_window.show_all();
|
app_window.show_all();
|
||||||
|
|
||||||
|
@ -144,6 +141,11 @@ fn try_main() -> Result<()> {
|
||||||
window.move_(window_def.position.0, window_def.position.1);
|
window.move_(window_def.position.0, window_def.position.1);
|
||||||
window.show();
|
window.show();
|
||||||
window.raise();
|
window.raise();
|
||||||
|
};
|
||||||
|
if let Err(err) = result {
|
||||||
|
eprintln!("{:?}", err);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
application.run(&[]);
|
application.run(&[]);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use derive_more::From;
|
|
||||||
use derive_more::*;
|
use derive_more::*;
|
||||||
use hocon::Hocon;
|
use hocon::Hocon;
|
||||||
use try_match::try_match;
|
use try_match::try_match;
|
||||||
|
@ -13,6 +12,12 @@ pub enum PrimitiveValue {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&str> for PrimitiveValue {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
PrimitiveValue::String(s.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PrimitiveValue {
|
impl PrimitiveValue {
|
||||||
pub fn as_string(&self) -> Result<&String> {
|
pub fn as_string(&self) -> Result<&String> {
|
||||||
try_match!(PrimitiveValue::String(x) = self).map_err(|x| anyhow!("{:?} is not a string", x))
|
try_match!(PrimitiveValue::String(x) = self).map_err(|x| anyhow!("{:?} is not a string", x))
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::build;
|
|
||||||
use crate::config::element;
|
use crate::config::element;
|
||||||
use crate::eww_state::*;
|
use crate::eww_state::*;
|
||||||
use crate::value::AttrValue;
|
use crate::value::{AttrValue, PrimitiveValue};
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use std::{collections::HashMap, process::Command};
|
use std::{collections::HashMap, process::Command};
|
||||||
|
@ -10,21 +9,41 @@ const CMD_STRING_PLACEHODLER: &str = "{}";
|
||||||
|
|
||||||
macro_rules! resolve {
|
macro_rules! resolve {
|
||||||
($args:ident, $gtk_widget:ident, {
|
($args:ident, $gtk_widget:ident, {
|
||||||
$($func:ident =>
|
$($func:ident => {
|
||||||
{
|
$($attr:literal $([$default:literal])? $(req $(@$required:tt)?)? => |$arg:ident| $body:expr),+ $(,)?
|
||||||
$($attr:literal => |$arg:ident| $body:expr),+
|
}),+ $(,)?
|
||||||
}
|
|
||||||
),+
|
|
||||||
}) => {
|
}) => {
|
||||||
$(
|
$($(
|
||||||
$(
|
resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body);
|
||||||
|
)+)+
|
||||||
|
};
|
||||||
|
|
||||||
|
// optional
|
||||||
|
($args:ident, $gtk_widget:ident, $func:ident => $attr:literal => |$arg:ident| $body:expr) => {
|
||||||
|
if let Some(attr_value) = $args.widget.attrs.get($attr) {
|
||||||
|
$args.eww_state.$func($args.local_env, attr_value, {
|
||||||
|
let $gtk_widget = $gtk_widget.clone();
|
||||||
|
move |$arg| { $body; }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// required
|
||||||
|
($args:ident, $gtk_widget:ident, $func:ident => $attr:literal req => |$arg:ident| $body:expr) => {
|
||||||
$args.eww_state.$func($args.local_env, $args.widget.get_attr($attr)?, {
|
$args.eww_state.$func($args.local_env, $args.widget.get_attr($attr)?, {
|
||||||
let $gtk_widget = $gtk_widget.clone();
|
let $gtk_widget = $gtk_widget.clone();
|
||||||
move |$arg| { $body; }
|
move |$arg| { $body; }
|
||||||
});
|
});
|
||||||
)+
|
};
|
||||||
)+
|
|
||||||
}
|
// with default
|
||||||
|
($args:ident, $gtk_widget:ident, $func:ident => $attr:literal [$default:expr] => |$arg:ident| $body:expr) => {
|
||||||
|
$args.eww_state.$func($args.local_env, $args.widget.attrs.get($attr).unwrap_or(&AttrValue::Concrete(PrimitiveValue::from($default))), {
|
||||||
|
let $gtk_widget = $gtk_widget.clone();
|
||||||
|
move |$arg| { $body; }
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_command<T: std::fmt::Display>(cmd: &str, arg: T) {
|
fn run_command<T: std::fmt::Display>(cmd: &str, arg: T) {
|
||||||
|
@ -44,23 +63,17 @@ pub fn element_to_gtk_thing(
|
||||||
element::ElementUse::Text(text) => Ok(gtk::Label::new(Some(&text)).upcast()),
|
element::ElementUse::Text(text) => Ok(gtk::Label::new(Some(&text)).upcast()),
|
||||||
element::ElementUse::Widget(widget) => {
|
element::ElementUse::Widget(widget) => {
|
||||||
let gtk_container =
|
let gtk_container =
|
||||||
build_gtk_widget_or_container(widget_definitions, eww_state, local_env, widget);
|
build_gtk_widget_or_container(widget_definitions, eww_state, local_env, widget)?;
|
||||||
let gtk_widget = gtk_container.or_else(|_| {
|
|
||||||
if let Some(def) = widget_definitions.get(widget.name.as_str()) {
|
|
||||||
let local_environment = build!(env = local_env.clone(); {
|
|
||||||
env.extend(widget.attrs.clone());
|
|
||||||
});
|
|
||||||
|
|
||||||
element_to_gtk_thing(
|
let gtk_widget = if let Some(gtk_container) = gtk_container {
|
||||||
widget_definitions,
|
gtk_container
|
||||||
eww_state,
|
} else if let Some(def) = widget_definitions.get(widget.name.as_str()) {
|
||||||
&local_environment,
|
let mut local_env = local_env.clone();
|
||||||
&def.structure,
|
local_env.extend(widget.attrs.clone());
|
||||||
)
|
element_to_gtk_thing(widget_definitions, eww_state, &local_env, &def.structure)?
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("unknown widget {}", &widget.name))
|
return Err(anyhow!("unknown widget: '{}'", &widget.name));
|
||||||
}
|
};
|
||||||
})?;
|
|
||||||
|
|
||||||
if let Ok(css_class) = widget
|
if let Ok(css_class) = widget
|
||||||
.get_attr("class")
|
.get_attr("class")
|
||||||
|
@ -85,24 +98,29 @@ pub fn build_gtk_widget_or_container(
|
||||||
eww_state: &mut EwwState,
|
eww_state: &mut EwwState,
|
||||||
local_env: &HashMap<String, AttrValue>,
|
local_env: &HashMap<String, AttrValue>,
|
||||||
widget: &element::WidgetUse,
|
widget: &element::WidgetUse,
|
||||||
) -> Result<gtk::Widget> {
|
) -> Result<Option<gtk::Widget>> {
|
||||||
let mut builder_args = BuilderArgs {
|
let mut builder_args = BuilderArgs {
|
||||||
eww_state,
|
eww_state,
|
||||||
local_env: &local_env,
|
local_env: &local_env,
|
||||||
widget: &widget,
|
widget: &widget,
|
||||||
};
|
};
|
||||||
let gtk_widget: Option<gtk::Widget> =
|
|
||||||
if let Some(gtk_widget) = build_gtk_container(&mut builder_args)? {
|
if let Some(gtk_widget) = build_gtk_container(&mut builder_args)? {
|
||||||
for child in &widget.children {
|
for child in &widget.children {
|
||||||
let child_widget =
|
let child_widget =
|
||||||
&element_to_gtk_thing(widget_definitions, eww_state, local_env, child)?;
|
&element_to_gtk_thing(widget_definitions, eww_state, local_env, child)
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"error while building child '{:?}' of '{:?}'",
|
||||||
|
&child,
|
||||||
|
>k_widget.get_widget_name()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
gtk_widget.add(child_widget);
|
gtk_widget.add(child_widget);
|
||||||
}
|
}
|
||||||
Some(gtk_widget.upcast())
|
Ok(Some(gtk_widget.upcast()))
|
||||||
} else {
|
} else {
|
||||||
build_gtk_widget(&mut builder_args)?
|
build_gtk_widget(&mut builder_args).context("error building gtk widget")
|
||||||
};
|
}
|
||||||
gtk_widget.context(format!("unknown widget {:?}", widget))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// widget definitions
|
// widget definitions
|
||||||
|
@ -134,7 +152,7 @@ fn build_gtk_scale(builder_args: &mut BuilderArgs) -> Result<gtk::Scale> {
|
||||||
|
|
||||||
resolve!(builder_args, gtk_widget, {
|
resolve!(builder_args, gtk_widget, {
|
||||||
resolve_f64 => {
|
resolve_f64 => {
|
||||||
"value" => |v| gtk_widget.set_value(v),
|
"value" req => |v| gtk_widget.set_value(v),
|
||||||
"min" => |v| gtk_widget.get_adjustment().set_lower(v),
|
"min" => |v| gtk_widget.get_adjustment().set_lower(v),
|
||||||
"max" => |v| gtk_widget.get_adjustment().set_upper(v)
|
"max" => |v| gtk_widget.get_adjustment().set_upper(v)
|
||||||
},
|
},
|
||||||
|
@ -153,7 +171,7 @@ fn build_gtk_button(builder_args: &mut BuilderArgs) -> Result<gtk::Button> {
|
||||||
let gtk_widget = gtk::Button::new();
|
let gtk_widget = gtk::Button::new();
|
||||||
resolve!(builder_args, gtk_widget, {
|
resolve!(builder_args, gtk_widget, {
|
||||||
resolve_bool => {
|
resolve_bool => {
|
||||||
"active" => |v| gtk_widget.set_sensitive(v)
|
"active" [true] => |v| gtk_widget.set_sensitive(v)
|
||||||
},
|
},
|
||||||
resolve_string => {
|
resolve_string => {
|
||||||
"onclick" => |cmd| gtk_widget.connect_clicked(move |_| run_command(&cmd, ""))
|
"onclick" => |cmd| gtk_widget.connect_clicked(move |_| run_command(&cmd, ""))
|
||||||
|
@ -166,9 +184,8 @@ fn build_gtk_layout(builder_args: &mut BuilderArgs) -> Result<gtk::Box> {
|
||||||
let gtk_widget = gtk::Box::new(gtk::Orientation::Horizontal, 0);
|
let gtk_widget = gtk::Box::new(gtk::Orientation::Horizontal, 0);
|
||||||
resolve!(builder_args, gtk_widget, {
|
resolve!(builder_args, gtk_widget, {
|
||||||
resolve_f64 => {
|
resolve_f64 => {
|
||||||
"spacing" => |v| gtk_widget.set_spacing(v as i32)
|
"spacing" [10.0] => |v| gtk_widget.set_spacing(v as i32)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(gtk_widget)
|
Ok(gtk_widget)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue