From 6b5c35cbf9e921beb68b4a108762775f3674acf5 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Sat, 21 May 2022 15:06:42 +0200 Subject: [PATCH] Add EWW_CONFIG_DIR, EWW_CMD, EWW_EXECUTABLE variables --- CHANGELOG.md | 1 + crates/eww/src/app.rs | 2 +- crates/eww/src/config/eww_config.rs | 36 +++++--- crates/eww/src/config/inbuilt.rs | 138 ++++++++++++++++++---------- crates/eww/src/server.rs | 2 +- 5 files changed, 113 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68a20a4..53edcad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ All notable changes to eww will be listed here, starting at changes since versio - Add `matches` function - Add transform widget (By: druskus20) - Add `:onaccept` to input field, add `:onclick` to eventbox +- Add `EWW_CMD`, `EWW_CONFIG_DIR`, `EWW_EXECUTABLE` magic variables ### Notable Internal changes - Rework state management completely, now making local state and dynamic widget hierarchy changes possible. diff --git a/crates/eww/src/app.rs b/crates/eww/src/app.rs index e0c80a7..174fa4c 100644 --- a/crates/eww/src/app.rs +++ b/crates/eww/src/app.rs @@ -126,7 +126,7 @@ impl App { DaemonCommand::ReloadConfigAndCss(sender) => { let mut errors = Vec::new(); - let config_result = config::read_from_file(&self.paths.get_yuck_path()); + let config_result = config::read_from_eww_paths(&self.paths); if let Err(e) = config_result.and_then(|new_config| self.load_config(new_config)) { errors.push(e) } diff --git a/crates/eww/src/config/eww_config.rs b/crates/eww/src/config/eww_config.rs index d1f3e42..921e200 100644 --- a/crates/eww/src/config/eww_config.rs +++ b/crates/eww/src/config/eww_config.rs @@ -1,6 +1,6 @@ use anyhow::{bail, Context, Result}; use eww_shared_util::VarName; -use std::{collections::HashMap, path::Path}; +use std::collections::HashMap; use yuck::{ config::{ file_provider::YuckFiles, script_var_definition::ScriptVarDefinition, validate::ValidationError, @@ -11,14 +11,15 @@ use yuck::{ use simplexpr::dynval::DynVal; -use crate::error_handling_ctx; +use crate::{config::inbuilt, error_handling_ctx, widgets::widget_definitions, EwwPaths}; use super::script_var; -/// Load an [EwwConfig] from a given file, resetting and applying the global YuckFiles object in [`crate::error_handling_ctx`]. -pub fn read_from_file(path: impl AsRef) -> Result { +/// Load an [`EwwConfig`] from the config dir of the given [`crate::EwwPaths`], +/// resetting and applying the global YuckFiles object in [`crate::error_handling_ctx`]. +pub fn read_from_eww_paths(eww_paths: &EwwPaths) -> Result { error_handling_ctx::clear_files(); - EwwConfig::read_from_file(&mut error_handling_ctx::YUCK_FILES.write().unwrap(), path) + EwwConfig::read_from_dir(&mut error_handling_ctx::YUCK_FILES.write().unwrap(), eww_paths) } /// Eww configuration structure. @@ -46,25 +47,34 @@ impl Default for EwwConfig { } impl EwwConfig { - pub fn read_from_file(files: &mut YuckFiles, path: impl AsRef) -> Result { - if !path.as_ref().exists() { - bail!("The configuration file `{}` does not exist", path.as_ref().display()); + /// Load an [`EwwConfig`] from the config dir of the given [`crate::EwwPaths`], reading the main config file. + pub fn read_from_dir(files: &mut YuckFiles, eww_paths: &EwwPaths) -> Result { + let yuck_path = eww_paths.get_yuck_path(); + if !yuck_path.exists() { + bail!("The configuration file `{}` does not exist", yuck_path.display()); } - let config = Config::generate_from_main_file(files, path)?; + let config = Config::generate_from_main_file(files, yuck_path)?; // run some validations on the configuration - yuck::config::validate::validate(&config, super::inbuilt::get_inbuilt_vars().keys().cloned().collect())?; + let magic_globals: Vec<_> = inbuilt::MAGIC_CONSTANT_NAMES + .into_iter() + .chain(inbuilt::MAGIC_CONSTANT_NAMES) + .into_iter() + .map(|x| VarName::from(x.clone())) + .collect(); + yuck::config::validate::validate(&config, magic_globals)?; for (name, def) in &config.widget_definitions { - if crate::widgets::widget_definitions::BUILTIN_WIDGET_NAMES.contains(&name.as_str()) { + if widget_definitions::BUILTIN_WIDGET_NAMES.contains(&name.as_str()) { return Err( AstError::ValidationError(ValidationError::AccidentalBuiltinOverride(def.span, name.to_string())).into() ); } } - let Config { widget_definitions, window_definitions, var_definitions, mut script_vars } = config; - script_vars.extend(crate::config::inbuilt::get_inbuilt_vars()); + let Config { widget_definitions, window_definitions, mut var_definitions, mut script_vars } = config; + script_vars.extend(inbuilt::get_inbuilt_vars()); + var_definitions.extend(inbuilt::get_magic_constants(eww_paths)); let mut poll_var_links = HashMap::>::new(); script_vars diff --git a/crates/eww/src/config/inbuilt.rs b/crates/eww/src/config/inbuilt.rs index 26a1a46..67f3e22 100644 --- a/crates/eww/src/config/inbuilt.rs +++ b/crates/eww/src/config/inbuilt.rs @@ -1,60 +1,96 @@ use std::{collections::HashMap, time::Duration}; use simplexpr::{dynval::DynVal, SimplExpr}; -use yuck::config::script_var_definition::{PollScriptVar, ScriptVarDefinition, VarSource}; +use yuck::config::{ + script_var_definition::{PollScriptVar, ScriptVarDefinition, VarSource}, + var_definition::VarDefinition, +}; -use crate::config::system_stats::*; +use crate::{config::system_stats::*, EwwPaths}; use eww_shared_util::VarName; -macro_rules! builtin_vars { - ($interval:expr, $($name:literal => $fun:expr),*$(,)?) => {{ - maplit::hashmap! { - $( - VarName::from($name) => ScriptVarDefinition::Poll(PollScriptVar { - name: VarName::from($name), - run_while_expr: SimplExpr::Literal(DynVal::from(true)), - run_while_var_refs: Vec::new(), - command: VarSource::Function($fun), - initial_value: None, - interval: $interval, - name_span: eww_shared_util::span::Span::DUMMY, - }) - ),* - } - }}} - -pub fn get_inbuilt_vars() -> HashMap { - builtin_vars! {Duration::new(2, 0), - // @desc EWW_TEMPS - Heat of the components in Celcius - // @prop { : temperature } - "EWW_TEMPS" => || Ok(DynVal::from(get_temperatures())), - - // @desc EWW_RAM - Information on ram and swap usage in kB. - // @prop { total_mem, free_mem, total_swap, free_swap, available_mem, used_mem, used_mem_perc } - "EWW_RAM" => || Ok(DynVal::from(get_ram())), - - // @desc EWW_DISK - Information on on all mounted partitions (Might report inaccurately on some filesystems, like btrfs)\nExample: `{EWW_DISK["/"]}` - // @prop { : { name, total, free, used, used_perc } } - "EWW_DISK" => || Ok(DynVal::from(get_disks())), - - // @desc EWW_BATTERY - Battery capacity in procent of the main battery - // @prop { : { capacity, status } } - "EWW_BATTERY" => || Ok(DynVal::from( - match get_battery_capacity() { - Err(e) => { - log::error!("Couldn't get the battery capacity: {:?}", e); - "Error: Check `eww log` for more details".to_string() - } - Ok(o) => o, +macro_rules! define_builtin_vars { + ($interval:expr, $($name:literal => $fun:expr),*$(,)?) => { + pub static INBUILT_VAR_NAMES: &[&'static str] = &[$($name),*]; + pub fn get_inbuilt_vars() -> HashMap { + maplit::hashmap! { + $( + VarName::from($name) => ScriptVarDefinition::Poll(PollScriptVar { + name: VarName::from($name), + run_while_expr: SimplExpr::Literal(DynVal::from(true)), + run_while_var_refs: Vec::new(), + command: VarSource::Function($fun), + initial_value: None, + interval: $interval, + name_span: eww_shared_util::span::Span::DUMMY, + }) + ),* } - )), - - // @desc EWW_CPU - Information on the CPU cores: frequency and usage (No MacOS support) - // @prop { cores: [{ core, freq, usage }], avg } - "EWW_CPU" => || Ok(DynVal::from(get_cpus())), - - // @desc EWW_NET - Bytes up/down on all interfaces - // @prop { : { up, down } } - "EWW_NET" => || Ok(DynVal::from(net())), + } } } + +define_builtin_vars! { Duration::new(2, 0), + // @desc EWW_TEMPS - Heat of the components in Celcius + // @prop { : temperature } + "EWW_TEMPS" => || Ok(DynVal::from(get_temperatures())), + + // @desc EWW_RAM - Information on ram and swap usage in kB. + // @prop { total_mem, free_mem, total_swap, free_swap, available_mem, used_mem, used_mem_perc } + "EWW_RAM" => || Ok(DynVal::from(get_ram())), + + // @desc EWW_DISK - Information on on all mounted partitions (Might report inaccurately on some filesystems, like btrfs)\nExample: `{EWW_DISK["/"]}` + // @prop { : { name, total, free, used, used_perc } } + "EWW_DISK" => || Ok(DynVal::from(get_disks())), + + // @desc EWW_BATTERY - Battery capacity in procent of the main battery + // @prop { : { capacity, status } } + "EWW_BATTERY" => || Ok(DynVal::from( + match get_battery_capacity() { + Err(e) => { + log::error!("Couldn't get the battery capacity: {:?}", e); + "Error: Check `eww log` for more details".to_string() + } + Ok(o) => o, + } + )), + + // @desc EWW_CPU - Information on the CPU cores: frequency and usage (No MacOS support) + // @prop { cores: [{ core, freq, usage }], avg } + "EWW_CPU" => || Ok(DynVal::from(get_cpus())), + + // @desc EWW_NET - Bytes up/down on all interfaces + // @prop { : { up, down } } + "EWW_NET" => || Ok(DynVal::from(net())), +} + +macro_rules! define_magic_constants { + ($eww_paths:ident, $($name:literal => $value:expr),*$(,)?) => { + pub static MAGIC_CONSTANT_NAMES: &[&'static str] = &[$($name),*]; + pub fn get_magic_constants($eww_paths: &EwwPaths) -> HashMap { + maplit::hashmap! { + $(VarName::from($name) => VarDefinition { + name: VarName::from($name), + initial_value: $value, + span: eww_shared_util::span::Span::DUMMY + }),* + } + } + } +} +define_magic_constants! { eww_paths, + // @desc EWW_CONFIG_DIR - Path to the eww configuration of the current process + "EWW_CONFIG_DIR" => DynVal::from_string(eww_paths.get_config_dir().to_string_lossy().into_owned()), + + // @desc EWW_CMD - eww command running in the current configuration, useful in event handlers. I.e.: `:onclick "${EWW_CMD} update foo=bar"` + "EWW_CMD" => DynVal::from_string( + format!("\"{}\" --config \"{}\"", + std::env::current_exe().map(|x| x.to_string_lossy().into_owned()).unwrap_or_else(|_| "eww".to_string()), + eww_paths.get_config_dir().to_string_lossy().into_owned() + ) + ), + // @desc EWW_EXECUTABLE - Full path of the eww executable + "EWW_EXECUTABLE" => DynVal::from_string( + std::env::current_exe().map(|x| x.to_string_lossy().into_owned()).unwrap_or_else(|_| "eww".to_string()), + ), +} diff --git a/crates/eww/src/server.rs b/crates/eww/src/server.rs index de2006c..9920dcb 100644 --- a/crates/eww/src/server.rs +++ b/crates/eww/src/server.rs @@ -24,7 +24,7 @@ pub fn initialize_server(paths: EwwPaths, action: Option, should_ log::info!("Loading paths: {}", &paths); - let read_config = config::read_from_file(&paths.get_yuck_path()); + let read_config = config::read_from_eww_paths(&paths); let eww_config = match read_config { Ok(config) => config,