Add unknown attribute warning

This commit is contained in:
elkowar 2020-10-04 12:46:05 +02:00
parent 4e69eb6390
commit 40fe82b4a0
7 changed files with 150 additions and 47 deletions

49
Cargo.lock generated
View file

@ -280,6 +280,19 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "env_logger"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime",
"log 0.4.11",
"regex",
"termcolor",
]
[[package]] [[package]]
name = "eww" name = "eww"
version = "0.1.0" version = "0.1.0"
@ -297,10 +310,12 @@ dependencies = [
"hotwatch", "hotwatch",
"ipc-channel", "ipc-channel",
"itertools", "itertools",
"log 0.4.11",
"maplit", "maplit",
"notify", "notify",
"num", "num",
"pretty_assertions", "pretty_assertions",
"pretty_env_logger",
"regex", "regex",
"roxmltree", "roxmltree",
"scheduled-executor", "scheduled-executor",
@ -762,6 +777,15 @@ dependencies = [
"notify", "notify",
] ]
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.6.0" version = "1.6.0"
@ -1259,6 +1283,16 @@ dependencies = [
"output_vt100", "output_vt100",
] ]
[[package]]
name = "pretty_env_logger"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
dependencies = [
"env_logger",
"log 0.4.11",
]
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "0.1.5" version = "0.1.5"
@ -1313,6 +1347,12 @@ dependencies = [
"unicode-xid 0.2.1", "unicode-xid 0.2.1",
] ]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]] [[package]]
name = "quote" name = "quote"
version = "0.3.15" version = "0.3.15"
@ -1639,6 +1679,15 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "textwrap" name = "textwrap"
version = "0.11.0" version = "0.11.0"

View file

@ -31,6 +31,8 @@ roxmltree = "0.13"
itertools = "0.9" itertools = "0.9"
scheduled-executor = "0.4" scheduled-executor = "0.4"
debug_stub_derive = "0.3" debug_stub_derive = "0.3"
log = "0.4"
pretty_env_logger = "0.4"
#thiserror = "1.0" #thiserror = "1.0"

View file

@ -1,5 +1,6 @@
use crate::*; use crate::*;
use debug_stub_derive::*; use debug_stub_derive::*;
use script_var_handler::*;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug)] #[derive(Debug)]
@ -16,12 +17,9 @@ pub struct App {
pub eww_config: config::EwwConfig, pub eww_config: config::EwwConfig,
pub windows: HashMap<String, gtk::Window>, pub windows: HashMap<String, gtk::Window>,
pub css_provider: gtk::CssProvider, pub css_provider: gtk::CssProvider,
#[debug_stub = "script-var poll script handles"]
pub script_var_poll_handles: Vec<scheduled_executor::executor::TaskHandle>,
#[debug_stub = "script-var poll executor"]
pub script_var_poll_executor: scheduled_executor::CoreExecutor,
pub app_evt_send: glib::Sender<EwwEvent>, pub app_evt_send: glib::Sender<EwwEvent>,
#[debug_stub = "ScriptVarHandler(...)"]
pub script_var_handler: ScriptVarHandler,
} }
impl App { impl App {
@ -35,6 +33,7 @@ impl App {
} }
pub fn handle_event(&mut self, event: EwwEvent) { pub fn handle_event(&mut self, event: EwwEvent) {
log::debug!("Handling event: {:?}", &event);
let result: Result<_> = try { let result: Result<_> = try {
match event { match event {
EwwEvent::UserCommand(command) => self.handle_user_command(command)?, EwwEvent::UserCommand(command) => self.handle_user_command(command)?,
@ -109,9 +108,7 @@ impl App {
pub fn reload_all_windows(&mut self, config: config::EwwConfig) -> Result<()> { pub fn reload_all_windows(&mut self, config: config::EwwConfig) -> Result<()> {
// refresh script-var poll stuff // refresh script-var poll stuff
self.script_var_poll_handles.iter().for_each(|handle| handle.stop()); if let Err(e) = self.script_var_handler.setup_command_poll_tasks(&config) {
self.script_var_poll_handles.clear();
if let Err(e) = self.init_command_poll_tasks() {
eprintln!("Error while setting up script-var commands: {:?}", e); eprintln!("Error while setting up script-var commands: {:?}", e);
} }
@ -130,33 +127,6 @@ impl App {
self.css_provider.load_from_data(css.as_bytes())?; self.css_provider.load_from_data(css.as_bytes())?;
Ok(()) Ok(())
} }
pub fn init_command_poll_tasks(&mut self) -> Result<()> {
let evt_send = self.app_evt_send.clone();
self.script_var_poll_handles = self
.eww_config
.get_script_vars()
.iter()
.map(|var| {
self.script_var_poll_executor.schedule_fixed_interval(
std::time::Duration::from_secs(0),
var.interval,
glib::clone!(@strong var, @strong evt_send => move |_| {
let result = eww_state::run_command(&var.command);
match result {
Ok(value) => {
let _ = evt_send.send(app::EwwEvent::UpdateVar(var.name.clone(), value));
}
Err(e) => {
eprintln!("Error while running script-var command: {:?}", e);
}
}
}),
)
})
.collect_vec();
Ok(())
}
} }
fn on_screen_changed(window: &gtk::Window, _old_screen: Option<&gdk::Screen>) { fn on_screen_changed(window: &gtk::Window, _old_screen: Option<&gdk::Screen>) {

View file

@ -10,8 +10,8 @@ use gdk::*;
use gtk::prelude::*; use gtk::prelude::*;
use hotwatch; use hotwatch;
use ipc_channel::ipc; use ipc_channel::ipc;
use itertools::Itertools; use log;
use scheduled_executor; use pretty_env_logger;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -21,6 +21,7 @@ use value::PrimitiveValue;
pub mod app; pub mod app;
pub mod config; pub mod config;
pub mod eww_state; pub mod eww_state;
pub mod script_var_handler;
pub mod util; pub mod util;
pub mod value; pub mod value;
pub mod widgets; pub mod widgets;
@ -44,6 +45,7 @@ macro_rules! try_logging_errors {
} }
fn main() { fn main() {
pretty_env_logger::init();
if let Err(e) = try_main() { if let Err(e) = try_main() {
eprintln!("{:?}", e); eprintln!("{:?}", e);
} }
@ -71,9 +73,12 @@ pub enum OptAction {
fn try_main() -> Result<()> { fn try_main() -> Result<()> {
let opts: Opt = StructOpt::from_args(); let opts: Opt = StructOpt::from_args();
log::info!("Trying to find server process");
if let Ok(sender) = find_server_process() { if let Ok(sender) = find_server_process() {
log::info!("Forwarding options to server");
sender.send(opts)?; sender.send(opts)?;
} else { } else {
log::info!("No instance found... Initializing server.");
initialize_server(opts)?; initialize_server(opts)?;
} }
Ok(()) Ok(())
@ -102,18 +107,21 @@ fn initialize_server(opts: Opt) -> Result<()> {
.to_path_buf(); .to_path_buf();
let scss_file_path = config_dir.join("eww.scss"); let scss_file_path = config_dir.join("eww.scss");
log::info!("reading configuration from {:?}", &config_file_path);
let eww_config = config::EwwConfig::read_from_file(&config_file_path)?; let eww_config = config::EwwConfig::read_from_file(&config_file_path)?;
gtk::init()?; gtk::init()?;
let (evt_send, evt_recv) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); let (evt_send, evt_recv) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let mut script_var_handler = script_var_handler::ScriptVarHandler::new(evt_send.clone())?;
script_var_handler.setup_command_poll_tasks(&eww_config)?;
let mut app = app::App { let mut app = app::App {
eww_state: EwwState::from_default_vars(eww_config.generate_initial_state()?.clone()), eww_state: EwwState::from_default_vars(eww_config.generate_initial_state()?.clone()),
eww_config, eww_config,
windows: HashMap::new(), windows: HashMap::new(),
css_provider: gtk::CssProvider::new(), css_provider: gtk::CssProvider::new(),
script_var_poll_handles: Vec::new(), script_var_handler,
script_var_poll_executor: scheduled_executor::CoreExecutor::new()?,
app_evt_send: evt_send.clone(), app_evt_send: evt_send.clone(),
}; };
@ -131,8 +139,6 @@ fn initialize_server(opts: Opt) -> Result<()> {
run_server_thread(evt_send.clone()); run_server_thread(evt_send.clone());
let _hotwatch = run_filewatch_thread(&config_file_path, &scss_file_path, evt_send.clone())?; let _hotwatch = run_filewatch_thread(&config_file_path, &scss_file_path, evt_send.clone())?;
app.init_command_poll_tasks()?;
evt_recv.attach(None, move |msg| { evt_recv.attach(None, move |msg| {
app.handle_event(msg); app.handle_event(msg);
glib::Continue(true) glib::Continue(true)
@ -145,11 +151,13 @@ fn initialize_server(opts: Opt) -> Result<()> {
fn run_server_thread(evt_send: glib::Sender<app::EwwEvent>) { fn run_server_thread(evt_send: glib::Sender<app::EwwEvent>) {
std::thread::spawn(move || { std::thread::spawn(move || {
log::info!("Starting up eww server");
let result: Result<_> = try { let result: Result<_> = try {
loop { loop {
let (ipc_server, instance_path): (ipc::IpcOneShotServer<Opt>, _) = ipc::IpcOneShotServer::new()?; let (ipc_server, instance_path): (ipc::IpcOneShotServer<Opt>, _) = ipc::IpcOneShotServer::new()?;
std::fs::write("/tmp/eww-instance-path", instance_path)?; std::fs::write("/tmp/eww-instance-path", instance_path)?;
let (_, initial) = ipc_server.accept()?; let (_, initial) = ipc_server.accept()?;
log::info!("received command from IPC: {:?}", &initial);
evt_send.send(app::EwwEvent::UserCommand(initial))?; evt_send.send(app::EwwEvent::UserCommand(initial))?;
} }
}; };
@ -165,11 +173,13 @@ fn run_filewatch_thread<P: AsRef<Path>>(
scss_file_path: P, scss_file_path: P,
evt_send: glib::Sender<app::EwwEvent>, evt_send: glib::Sender<app::EwwEvent>,
) -> Result<hotwatch::Hotwatch> { ) -> Result<hotwatch::Hotwatch> {
log::info!("Initializing config file watcher");
let mut hotwatch = hotwatch::Hotwatch::new()?; let mut hotwatch = hotwatch::Hotwatch::new()?;
let config_file_change_send = evt_send.clone(); let config_file_change_send = evt_send.clone();
hotwatch.watch_file_changes(config_file_path, move |path| { hotwatch.watch_file_changes(config_file_path, move |path| {
try_logging_errors!("handling change of config file" => { try_logging_errors!("handling change of config file" => {
log::info!("Reloading eww configuration");
let new_eww_config = config::EwwConfig::read_from_file(path)?; let new_eww_config = config::EwwConfig::read_from_file(path)?;
config_file_change_send.send(app::EwwEvent::ReloadConfig(new_eww_config))?; config_file_change_send.send(app::EwwEvent::ReloadConfig(new_eww_config))?;
}); });
@ -177,6 +187,7 @@ fn run_filewatch_thread<P: AsRef<Path>>(
let result = hotwatch.watch_file_changes(scss_file_path, move |path| { let result = hotwatch.watch_file_changes(scss_file_path, move |path| {
try_logging_errors!("handling change of scss file" => { try_logging_errors!("handling change of scss file" => {
log::info!("reloading eww css file");
let eww_css = util::parse_scss_from_file(path)?; let eww_css = util::parse_scss_from_file(path)?;
evt_send.send(app::EwwEvent::ReloadCss(eww_css))?; evt_send.send(app::EwwEvent::ReloadCss(eww_css))?;
}) })

48
src/script_var_handler.rs Normal file
View file

@ -0,0 +1,48 @@
use crate::{app, config, eww_state};
use anyhow::*;
use glib;
use itertools::Itertools;
use scheduled_executor;
pub struct ScriptVarHandler {
evt_send: glib::Sender<app::EwwEvent>,
pub poll_handles: Vec<scheduled_executor::executor::TaskHandle>,
pub poll_executor: scheduled_executor::CoreExecutor,
}
impl ScriptVarHandler {
pub fn new(evt_send: glib::Sender<app::EwwEvent>) -> Result<Self> {
log::info!("initializing handler for poll script vars");
Ok(ScriptVarHandler {
evt_send,
poll_handles: Vec::new(),
poll_executor: scheduled_executor::CoreExecutor::new()?,
})
}
/// clears and stops the currently running poll handles, then opens the new ones as configured
pub fn setup_command_poll_tasks(&mut self, config: &config::EwwConfig) -> Result<()> {
log::info!("reloading handler for poll script vars");
self.poll_handles.iter().for_each(|handle| handle.stop());
self.poll_handles.clear();
let evt_send = self.evt_send.clone();
self.poll_handles = config
.get_script_vars()
.iter()
.map(|var| {
self.poll_executor.schedule_fixed_interval(
std::time::Duration::from_secs(0),
var.interval,
glib::clone!(@strong var, @strong evt_send => move |_| {
let result = eww_state::run_command(&var.command)
.and_then(|output| Ok(evt_send.send(app::EwwEvent::UpdateVar(var.name.clone(), output))?));
if let Err(e) = result {
eprintln!("Error while running script-var command: {:?}", e);
}
}),
)
})
.collect_vec();
Ok(())
}
}

View file

@ -21,6 +21,7 @@ struct BuilderArgs<'a, 'b, 'c> {
eww_state: &'a mut EwwState, eww_state: &'a mut EwwState,
local_env: &'b HashMap<String, AttrValue>, local_env: &'b HashMap<String, AttrValue>,
widget: &'c element::WidgetUse, widget: &'c element::WidgetUse,
unhandled_attrs: Vec<&'c str>,
} }
pub fn element_to_gtk_thing( pub fn element_to_gtk_thing(
@ -56,6 +57,7 @@ pub fn build_gtk_widget(
eww_state, eww_state,
local_env, local_env,
widget, widget,
unhandled_attrs: widget.attrs.keys().map(|x| x.as_str()).collect(),
}; };
let gtk_widget = match widget_to_gtk_widget(&mut bargs) { let gtk_widget = match widget_to_gtk_widget(&mut bargs) {
Ok(Some(gtk_widget)) => gtk_widget, Ok(Some(gtk_widget)) => gtk_widget,
@ -82,6 +84,14 @@ pub fn build_gtk_widget(
.map(|w| resolve_orientable_attrs(&mut bargs, &w)); .map(|w| resolve_orientable_attrs(&mut bargs, &w));
resolve_widget_attrs(&mut bargs, &gtk_widget); resolve_widget_attrs(&mut bargs, &gtk_widget);
if !bargs.unhandled_attrs.is_empty() {
eprintln!(
"WARN: Unknown attribute used in {}: {}",
widget.name,
bargs.unhandled_attrs.join(", ")
)
}
Ok(Some(gtk_widget)) Ok(Some(gtk_widget))
} }
@ -91,24 +101,25 @@ macro_rules! resolve {
$( $(
$func:ident => $attr:literal $( = $default:literal)? $( = req $(@$required:tt)?)? => |$arg:ident| $body:expr $func:ident => $attr:literal $( = $default:literal)? $( = req $(@$required:tt)?)? => |$arg:ident| $body:expr
),+ $(,)? ),+ $(,)?
}) => { }) => {{
$( $(
resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body); resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body);
)+ )+
}; }};
($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 $(= $default:literal)? $(= req $(@$required:tt)?)? => |$arg:ident| $body:expr),+ $(,)?
}),+ $(,)? }),+ $(,)?
}) => { }) => {{
$($( $($(
resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body); resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body);
)+)+ )+)+
}; }};
// optional // optional
($args:ident, $gtk_widget:ident, $func:ident => $attr:literal => |$arg:ident| $body:expr) => { ($args:ident, $gtk_widget:ident, $func:ident => $attr:literal => |$arg:ident| $body:expr) => {
$args.unhandled_attrs.retain(|a| a != &$attr);
if let Some(attr_value) = $args.widget.attrs.get($attr) { if let Some(attr_value) = $args.widget.attrs.get($attr) {
$args.eww_state.$func($args.local_env, attr_value, { $args.eww_state.$func($args.local_env, attr_value, {
let $gtk_widget = $gtk_widget.clone(); let $gtk_widget = $gtk_widget.clone();
@ -119,6 +130,7 @@ macro_rules! resolve {
// required // required
($args:ident, $gtk_widget:ident, $func:ident => $attr:literal req => |$arg:ident| $body:expr) => { ($args:ident, $gtk_widget:ident, $func:ident => $attr:literal req => |$arg:ident| $body:expr) => {
$args.unhandled_attrs.retain(|a| a != &$attr);
$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; }
@ -127,6 +139,7 @@ macro_rules! resolve {
// with default // with default
($args:ident, $gtk_widget:ident, $func:ident => $attr:literal [$default:expr] => |$arg:ident| $body:expr) => { ($args:ident, $gtk_widget:ident, $func:ident => $attr:literal [$default:expr] => |$arg:ident| $body:expr) => {
$args.unhandled_attrs.retain(|a| a != &$attr);
$args.eww_state.$func($args.local_env, $args.widget.attrs.get($attr).unwrap_or(&AttrValue::Concrete(PrimitiveValue::from($default))), { $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(); let $gtk_widget = $gtk_widget.clone();
move |$arg| { $body; } move |$arg| { $body; }

View file

@ -16,8 +16,10 @@ pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::Wi
resolve!(bargs, gtk_widget, { resolve!(bargs, gtk_widget, {
resolve_str => "class" => |v| gtk_widget.get_style_context().add_class(&v), resolve_str => "class" => |v| gtk_widget.get_style_context().add_class(&v),
resolve_bool => "active" = true => |v| gtk_widget.set_sensitive(v), resolve_bool => "active" = true => |v| gtk_widget.set_sensitive(v),
resolve_str => "valign" => |v| gtk_widget.set_valign(parse_align(&v)), resolve_str => "valign" => |v| gtk_widget.set_valign(parse_align(&v)),
resolve_str => "halign" => |v| gtk_widget.set_halign(parse_align(&v)), resolve_str => "halign" => |v| gtk_widget.set_halign(parse_align(&v)),
resolve_f64 => "width" => |v| gtk_widget.set_size_request(v as i32, gtk_widget.get_allocated_height()),
resolve_f64 => "height" => |v| gtk_widget.set_size_request(gtk_widget.get_allocated_width(), v as i32),
}); });
} }
@ -59,6 +61,7 @@ pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result<Option<gtk
"button" => build_gtk_button(bargs)?.upcast(), "button" => build_gtk_button(bargs)?.upcast(),
"label" => build_gtk_label(bargs)?.upcast(), "label" => build_gtk_label(bargs)?.upcast(),
"text" => build_gtk_text(bargs)?.upcast(), "text" => build_gtk_text(bargs)?.upcast(),
"aspect" => build_gtk_aspect_frame(bargs)?.upcast(),
_ => return Ok(None), _ => return Ok(None),
}; };
Ok(Some(gtk_widget)) Ok(Some(gtk_widget))
@ -129,6 +132,13 @@ fn build_gtk_text(bargs: &mut BuilderArgs) -> Result<gtk::Label> {
); );
Ok(gtk_widget) Ok(gtk_widget)
} }
fn build_gtk_aspect_frame(bargs: &mut BuilderArgs) -> Result<gtk::AspectFrame> {
let gtk_widget = gtk::AspectFrame::new(None, 0.5, 0.5, 1.0, true);
//resolve!(bargs, gtk_widget, {});
Ok(gtk_widget)
}
fn parse_orientation(o: &str) -> gtk::Orientation { fn parse_orientation(o: &str) -> gtk::Orientation {
match o { match o {
"vertical" | "v" => gtk::Orientation::Vertical, "vertical" | "v" => gtk::Orientation::Vertical,