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"
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]]
name = "eww"
version = "0.1.0"
@ -297,10 +310,12 @@ dependencies = [
"hotwatch",
"ipc-channel",
"itertools",
"log 0.4.11",
"maplit",
"notify",
"num",
"pretty_assertions",
"pretty_env_logger",
"regex",
"roxmltree",
"scheduled-executor",
@ -762,6 +777,15 @@ dependencies = [
"notify",
]
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error",
]
[[package]]
name = "indexmap"
version = "1.6.0"
@ -1259,6 +1283,16 @@ dependencies = [
"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]]
name = "proc-macro-crate"
version = "0.1.5"
@ -1313,6 +1347,12 @@ dependencies = [
"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]]
name = "quote"
version = "0.3.15"
@ -1639,6 +1679,15 @@ dependencies = [
"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]]
name = "textwrap"
version = "0.11.0"

View file

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

View file

@ -1,5 +1,6 @@
use crate::*;
use debug_stub_derive::*;
use script_var_handler::*;
use std::collections::HashMap;
#[derive(Debug)]
@ -16,12 +17,9 @@ pub struct App {
pub eww_config: config::EwwConfig,
pub windows: HashMap<String, gtk::Window>,
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>,
#[debug_stub = "ScriptVarHandler(...)"]
pub script_var_handler: ScriptVarHandler,
}
impl App {
@ -35,6 +33,7 @@ impl App {
}
pub fn handle_event(&mut self, event: EwwEvent) {
log::debug!("Handling event: {:?}", &event);
let result: Result<_> = try {
match event {
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<()> {
// refresh script-var poll stuff
self.script_var_poll_handles.iter().for_each(|handle| handle.stop());
self.script_var_poll_handles.clear();
if let Err(e) = self.init_command_poll_tasks() {
if let Err(e) = self.script_var_handler.setup_command_poll_tasks(&config) {
eprintln!("Error while setting up script-var commands: {:?}", e);
}
@ -130,33 +127,6 @@ impl App {
self.css_provider.load_from_data(css.as_bytes())?;
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>) {

View file

@ -10,8 +10,8 @@ use gdk::*;
use gtk::prelude::*;
use hotwatch;
use ipc_channel::ipc;
use itertools::Itertools;
use scheduled_executor;
use log;
use pretty_env_logger;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
@ -21,6 +21,7 @@ use value::PrimitiveValue;
pub mod app;
pub mod config;
pub mod eww_state;
pub mod script_var_handler;
pub mod util;
pub mod value;
pub mod widgets;
@ -44,6 +45,7 @@ macro_rules! try_logging_errors {
}
fn main() {
pretty_env_logger::init();
if let Err(e) = try_main() {
eprintln!("{:?}", e);
}
@ -71,9 +73,12 @@ pub enum OptAction {
fn try_main() -> Result<()> {
let opts: Opt = StructOpt::from_args();
log::info!("Trying to find server process");
if let Ok(sender) = find_server_process() {
log::info!("Forwarding options to server");
sender.send(opts)?;
} else {
log::info!("No instance found... Initializing server.");
initialize_server(opts)?;
}
Ok(())
@ -102,18 +107,21 @@ fn initialize_server(opts: Opt) -> Result<()> {
.to_path_buf();
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)?;
gtk::init()?;
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 {
eww_state: EwwState::from_default_vars(eww_config.generate_initial_state()?.clone()),
eww_config,
windows: HashMap::new(),
css_provider: gtk::CssProvider::new(),
script_var_poll_handles: Vec::new(),
script_var_poll_executor: scheduled_executor::CoreExecutor::new()?,
script_var_handler,
app_evt_send: evt_send.clone(),
};
@ -131,8 +139,6 @@ fn initialize_server(opts: Opt) -> Result<()> {
run_server_thread(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| {
app.handle_event(msg);
glib::Continue(true)
@ -145,11 +151,13 @@ fn initialize_server(opts: Opt) -> Result<()> {
fn run_server_thread(evt_send: glib::Sender<app::EwwEvent>) {
std::thread::spawn(move || {
log::info!("Starting up eww server");
let result: Result<_> = try {
loop {
let (ipc_server, instance_path): (ipc::IpcOneShotServer<Opt>, _) = ipc::IpcOneShotServer::new()?;
std::fs::write("/tmp/eww-instance-path", instance_path)?;
let (_, initial) = ipc_server.accept()?;
log::info!("received command from IPC: {:?}", &initial);
evt_send.send(app::EwwEvent::UserCommand(initial))?;
}
};
@ -165,11 +173,13 @@ fn run_filewatch_thread<P: AsRef<Path>>(
scss_file_path: P,
evt_send: glib::Sender<app::EwwEvent>,
) -> Result<hotwatch::Hotwatch> {
log::info!("Initializing config file watcher");
let mut hotwatch = hotwatch::Hotwatch::new()?;
let config_file_change_send = evt_send.clone();
hotwatch.watch_file_changes(config_file_path, move |path| {
try_logging_errors!("handling change of config file" => {
log::info!("Reloading eww configuration");
let new_eww_config = config::EwwConfig::read_from_file(path)?;
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| {
try_logging_errors!("handling change of scss file" => {
log::info!("reloading eww css file");
let eww_css = util::parse_scss_from_file(path)?;
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,
local_env: &'b HashMap<String, AttrValue>,
widget: &'c element::WidgetUse,
unhandled_attrs: Vec<&'c str>,
}
pub fn element_to_gtk_thing(
@ -56,6 +57,7 @@ pub fn build_gtk_widget(
eww_state,
local_env,
widget,
unhandled_attrs: widget.attrs.keys().map(|x| x.as_str()).collect(),
};
let gtk_widget = match widget_to_gtk_widget(&mut bargs) {
Ok(Some(gtk_widget)) => gtk_widget,
@ -82,6 +84,14 @@ pub fn build_gtk_widget(
.map(|w| resolve_orientable_attrs(&mut bargs, &w));
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))
}
@ -91,24 +101,25 @@ macro_rules! resolve {
$(
$func:ident => $attr:literal $( = $default:literal)? $( = req $(@$required:tt)?)? => |$arg:ident| $body:expr
),+ $(,)?
}) => {
}) => {{
$(
resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body);
)+
};
}};
($args:ident, $gtk_widget:ident, {
$($func:ident => {
$($attr:literal $(= $default:literal)? $(= req $(@$required:tt)?)? => |$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) => {
$args.unhandled_attrs.retain(|a| a != &$attr);
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();
@ -119,6 +130,7 @@ macro_rules! resolve {
// required
($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)?, {
let $gtk_widget = $gtk_widget.clone();
move |$arg| { $body; }
@ -127,6 +139,7 @@ macro_rules! resolve {
// with default
($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))), {
let $gtk_widget = $gtk_widget.clone();
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_str => "class" => |v| gtk_widget.get_style_context().add_class(&v),
resolve_bool => "active" = true => |v| gtk_widget.set_sensitive(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 => "valign" => |v| gtk_widget.set_valign(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(),
"label" => build_gtk_label(bargs)?.upcast(),
"text" => build_gtk_text(bargs)?.upcast(),
"aspect" => build_gtk_aspect_frame(bargs)?.upcast(),
_ => return Ok(None),
};
Ok(Some(gtk_widget))
@ -129,6 +132,13 @@ fn build_gtk_text(bargs: &mut BuilderArgs) -> Result<gtk::Label> {
);
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 {
match o {
"vertical" | "v" => gtk::Orientation::Vertical,