Add unknown attribute warning
This commit is contained in:
parent
4e69eb6390
commit
40fe82b4a0
7 changed files with 150 additions and 47 deletions
49
Cargo.lock
generated
49
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
40
src/app.rs
40
src/app.rs
|
@ -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: >k::Window, _old_screen: Option<&gdk::Screen>) {
|
||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -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
48
src/script_var_handler.rs
Normal 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(())
|
||||
}
|
||||
}
|
|
@ -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, >k_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; }
|
||||
|
|
|
@ -16,8 +16,10 @@ pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::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,
|
||||
|
|
Loading…
Add table
Reference in a new issue