Predefined variables/Magic vars (#117)
* basic idea * generates docs * hardcoded the gen script * trying to hide magic vars * eww-state is good now * structure for cpu var is now there * renamed cpu to diskstat, bc lib supports it after all * not going to implement disk IO. go back to this commit, to see a rough idea * removed it * formatting * stopped data race * Update src/config/system_stats/ram.rs Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com> * Update src/config/system_stats/disk.rs Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com> * Explains macos better * Update battery.rs * Function for each OS when getting battery, a bit cleaner * reworked battery a little * all in one big file * facepalm * cleaner gen script and one huge file for the system stat stuff * merge conflicts * github interface for resolving merge conflicts sucks, this fixes it * Apply suggestions from code review Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com> * Update src/config/inbuilt.rs Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com> * code suggestions * component temperature is a json struct * newlines in magic vars descriptions * disks is now json, numbers are not wrapped in strings, and more idiomatic code * Update gen-docs.ts Co-authored-by: mlvzk <mlvzk@protonmail.com> * removes a unneeded heading * more doc updates and EWW_CPU_USAGE is now json * calculates battery total avg and it's a json struct Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com> Co-authored-by: mlvzk <mlvzk@protonmail.com>
This commit is contained in:
parent
6eea3e039d
commit
df5793b204
15 changed files with 434 additions and 42 deletions
2
.github/workflows/gh-pages.yml
vendored
2
.github/workflows/gh-pages.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
|||
uses: denoland/setup-deno@main
|
||||
with:
|
||||
deno-version: "v1.x"
|
||||
- run: deno run --allow-read gen-docs.ts ./src/widgets/widget_definitions.rs >> ./docs/content/main/widgets.md
|
||||
- run: deno run --allow-read --allow-write gen-docs.ts ./src/widgets/widget_definitions.rs ./src/config/inbuilt.rs
|
||||
|
||||
# Build & deploy
|
||||
- name: shalzz/zola-deploy-action
|
||||
|
|
133
Cargo.lock
generated
133
Cargo.lock
generated
|
@ -71,7 +71,7 @@ checksum = "db134ba52475c060f3329a8ef0f8786d6b872ed01515d4b79c162e5798da1340"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -227,6 +227,12 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.1"
|
||||
|
@ -237,6 +243,30 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.4"
|
||||
|
@ -255,7 +285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d"
|
||||
dependencies = [
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -277,7 +307,7 @@ dependencies = [
|
|||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -286,6 +316,12 @@ version = "0.1.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.4"
|
||||
|
@ -353,6 +389,7 @@ dependencies = [
|
|||
"simple-signal",
|
||||
"smart-default",
|
||||
"structopt",
|
||||
"sysinfo",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
|
@ -370,7 +407,7 @@ dependencies = [
|
|||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -467,7 +504,7 @@ dependencies = [
|
|||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -693,7 +730,7 @@ dependencies = [
|
|||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -981,6 +1018,15 @@ version = "2.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.7.11"
|
||||
|
@ -1273,7 +1319,7 @@ dependencies = [
|
|||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1349,7 +1395,7 @@ dependencies = [
|
|||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
@ -1464,19 +1510,44 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.7"
|
||||
name = "rayon"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85dd92e586f7355c633911e11f77f3d12f04b1b1bd76a198bd34ae3af8341ef2"
|
||||
checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"crossbeam-deque",
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.2"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efb2352a0f4d4b128f734b5c44c79ff80117351138733f12f982fe3e2b13343"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -1485,9 +1556,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.24"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00efb87459ba4f6fb2169d20f68565555688e1250ee6825cdf6254f8b48fafb2"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
|
@ -1536,7 +1607,7 @@ checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1595,7 +1666,7 @@ checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1631,7 +1702,7 @@ dependencies = [
|
|||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1649,7 +1720,7 @@ dependencies = [
|
|||
"heck",
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1665,9 +1736,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.71"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373"
|
||||
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
|
@ -1683,6 +1754,22 @@ dependencies = [
|
|||
"unicode-xid 0.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.16.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567e910ef0207be81a4e1bb0491e9a8d9866cf45b20fe1a52c03d347da9ea51b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"core-foundation-sys",
|
||||
"doc-comment",
|
||||
"libc",
|
||||
"ntapi",
|
||||
"once_cell",
|
||||
"rayon",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "1.3.2"
|
||||
|
@ -1739,7 +1826,7 @@ checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1770,7 +1857,7 @@ checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.71",
|
||||
"syn 1.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -60,6 +60,7 @@ futures-core = "0.3"
|
|||
futures-util = "0.3"
|
||||
tokio-util = "0.6"
|
||||
|
||||
sysinfo = "0.16.1"
|
||||
|
||||
nom = "6.1"
|
||||
dyn-clone = "1.0"
|
||||
|
|
13
docs/content/main/magic-vars.md
Normal file
13
docs/content/main/magic-vars.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
+++
|
||||
title = "Magic Variables"
|
||||
slug = "magic variables documenation"
|
||||
weight = 3
|
||||
+++
|
||||
|
||||
These are variables that are always there, without you having to import them.
|
||||
|
||||
The delay between the updating variables is always 2s.
|
||||
|
||||
|
||||
## Updating magic variables
|
||||
|
|
@ -3,3 +3,4 @@ title = "Widgets"
|
|||
slug = "widget documentation"
|
||||
weight = 3
|
||||
+++
|
||||
|
||||
|
|
22
gen-docs.ts
22
gen-docs.ts
|
@ -12,6 +12,18 @@ interface Widget {
|
|||
isVisible: boolean;
|
||||
}
|
||||
|
||||
function parseMagicVariables(data: string) {
|
||||
const pattern = /^.*\/\/\s*@desc\s*(\w+)\s*-\s*(.*)$/gm;
|
||||
let output = [];
|
||||
for (const [_, name, desc] of data.matchAll(pattern)) {
|
||||
output.push(
|
||||
`### \`${name}\`
|
||||
${desc.replaceAll("\\n", "\n\n")}
|
||||
`);
|
||||
}
|
||||
return output.join("\n");
|
||||
}
|
||||
|
||||
function parseVars(code: string): Record<string, string> {
|
||||
const VAR_PATTERN = /^.*\/\/+ *@var +(.*?) +- +(.*)$/;
|
||||
const vars: Record<string, string> = {};
|
||||
|
@ -121,7 +133,7 @@ function printDocs(vars: Record<string, string>, docs: Record<string, Widget>) {
|
|||
.map((x) => printWidget(x))
|
||||
.map((x) => x.replace(/\$\w+/g, (x) => vars[x.replace("$", "")]))
|
||||
.join("\n\n");
|
||||
console.log(output);
|
||||
return output;
|
||||
}
|
||||
|
||||
function printWidget(widget: Widget) {
|
||||
|
@ -138,7 +150,13 @@ ${widget.props.map((prop) => `- **\`${prop.name}\`**: *\`${prop.type}\`* ${prop.
|
|||
// deno run --allow-read gen-docs.ts ./src/widgets/widget_definitions.ts 2> /dev/null
|
||||
Deno.readTextFile(Deno.args[0]).then(data => {
|
||||
const vars = parseVars(data);
|
||||
printDocs(vars, parseDocs(data));
|
||||
Deno.writeTextFile("docs/content/main/widgets.md", printDocs(vars, parseDocs(data)), {"append": true});
|
||||
}).catch(err => {
|
||||
return console.error(err);
|
||||
})
|
||||
|
||||
let magic = Deno.readTextFile(Deno.args[1]).then(data => {
|
||||
Deno.writeTextFile("docs/content/main/magic-vars.md", parseMagicVariables(data), {"append": true});
|
||||
}).catch(err => {
|
||||
return console.error(err);
|
||||
})
|
||||
|
|
18
src/app.rs
18
src/app.rs
|
@ -60,7 +60,10 @@ pub enum DaemonCommand {
|
|||
},
|
||||
KillServer,
|
||||
CloseAll,
|
||||
PrintState(DaemonResponseSender),
|
||||
PrintState {
|
||||
all: bool,
|
||||
sender: DaemonResponseSender,
|
||||
},
|
||||
PrintDebug(DaemonResponseSender),
|
||||
PrintWindows(DaemonResponseSender),
|
||||
}
|
||||
|
@ -157,9 +160,15 @@ impl App {
|
|||
let result = self.close_window(&window_name);
|
||||
respond_with_error(sender, result)?;
|
||||
}
|
||||
DaemonCommand::PrintState(sender) => {
|
||||
let output =
|
||||
self.eww_state.get_variables().iter().map(|(key, value)| format!("{}: {}", key, value)).join("\n");
|
||||
DaemonCommand::PrintState { all, sender } => {
|
||||
let vars = self.eww_state.get_variables().iter();
|
||||
let output = if all {
|
||||
vars.map(|(key, value)| format!("{}: {}", key, value)).join("\n")
|
||||
} else {
|
||||
vars.filter(|(x, _)| self.eww_state.referenced_vars().any(|var| x == &var))
|
||||
.map(|(key, value)| format!("{}: {}", key, value))
|
||||
.join("\n")
|
||||
};
|
||||
sender.send(DaemonResponse::Success(output)).context("sending response from main thread")?
|
||||
}
|
||||
DaemonCommand::PrintWindows(sender) => {
|
||||
|
@ -219,7 +228,6 @@ impl App {
|
|||
) -> Result<()> {
|
||||
// remove and close existing window with the same name
|
||||
let _ = self.close_window(window_name);
|
||||
|
||||
log::info!("Opening window {}", window_name);
|
||||
|
||||
let mut window_def = self.eww_config.get_window(window_name)?.clone();
|
||||
|
|
|
@ -90,7 +90,6 @@ impl RawEwwConfig {
|
|||
included_path.display()
|
||||
);
|
||||
};
|
||||
|
||||
for included_config in includes {
|
||||
for conflict in util::extend_safe(&mut eww_config.widgets, included_config.widgets) {
|
||||
log_conflict("widget", &conflict, &included_config.filepath)
|
||||
|
@ -197,6 +196,17 @@ fn parse_variables_block(xml: XmlElement) -> Result<(HashMap<VarName, PrimVal>,
|
|||
_ => bail!("Illegal element in variables block: {}", node.as_tag_string()),
|
||||
}
|
||||
}
|
||||
|
||||
// Extends the variables with the predefined variables
|
||||
let inbuilt = crate::config::inbuilt::get_inbuilt_vars();
|
||||
for i in util::extend_safe(&mut script_vars, inbuilt) {
|
||||
eprintln!(
|
||||
"script-var '{}' defined twice (defined in your config and in the eww included variables)\nHint: don't define any \
|
||||
varible like any of these: https://elkowar.github.io/eww/main/magic-variables-documenation/",
|
||||
i,
|
||||
);
|
||||
}
|
||||
|
||||
Ok((normal_vars, script_vars))
|
||||
}
|
||||
|
||||
|
@ -274,6 +284,6 @@ mod test {
|
|||
assert_eq!(merged_config.widgets.len(), 2);
|
||||
assert_eq!(merged_config.windows.len(), 2);
|
||||
assert_eq!(merged_config.initial_variables.len(), 2);
|
||||
assert_eq!(merged_config.script_vars.len(), 0);
|
||||
assert_eq!(merged_config.script_vars.len(), 7);
|
||||
}
|
||||
}
|
||||
|
|
48
src/config/inbuilt.rs
Normal file
48
src/config/inbuilt.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use crate::{
|
||||
config::{system_stats::*, PollScriptVar, ScriptVar, VarSource},
|
||||
value::{PrimVal as PrimitiveValue, VarName},
|
||||
};
|
||||
use std::{collections::HashMap, time::Duration};
|
||||
|
||||
macro_rules! builtin_vars {
|
||||
($interval:expr, $($name:literal => $fun:expr),*$(,)?) => {{
|
||||
maplit::hashmap! {
|
||||
$(
|
||||
VarName::from($name) => ScriptVar::Poll(PollScriptVar {
|
||||
name: VarName::from($name),
|
||||
command: VarSource::Function($fun),
|
||||
interval: $interval,
|
||||
})
|
||||
),*
|
||||
}
|
||||
}}}
|
||||
|
||||
pub fn get_inbuilt_vars() -> HashMap<VarName, ScriptVar> {
|
||||
builtin_vars! {Duration::new(2, 0),
|
||||
// @desc EWW_TEMPS - Heat of the components in Celcius\nExample: `{{(CPU_TEMPS.core_1 + CPU_TEMPS.core_2) / 2}}`
|
||||
"EWW_TEMPS" => || Ok(PrimitiveValue::from(cores())),
|
||||
|
||||
// @desc EWW_RAM - The current RAM + Swap usage
|
||||
"EWW_RAM" => || Ok(PrimitiveValue::from(format!("{:.2}", ram()))),
|
||||
|
||||
// @desc EWW_DISK - Information on on all mounted partitions (Might report inaccurately on some filesystems, like btrfs)\nExample: `{{EWW_DISK["/"]}}`
|
||||
"EWW_DISK" => || Ok(PrimitiveValue::from(disk())),
|
||||
|
||||
// @desc EWW_BATTERY - Battery capacity in procent of the main battery
|
||||
"EWW_BATTERY" => || Ok(PrimitiveValue::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_USAGE - Average CPU usage (all cores) since the last update (No MacOS support)
|
||||
"EWW_CPU_USAGE" => || Ok(PrimitiveValue::from(get_avg_cpu_usage())),
|
||||
|
||||
// @desc EWW_NET - Bytes up/down on all interfaces
|
||||
"EWW_NET" => || Ok(PrimitiveValue::from(net())),
|
||||
}
|
||||
}
|
|
@ -10,7 +10,9 @@ use xml_ext::*;
|
|||
|
||||
pub mod element;
|
||||
pub mod eww_config;
|
||||
pub mod inbuilt;
|
||||
pub mod script_var;
|
||||
pub mod system_stats;
|
||||
pub mod window_definition;
|
||||
pub mod window_geometry;
|
||||
pub mod xml_ext;
|
||||
|
|
|
@ -6,16 +6,24 @@ use crate::ensure_xml_tag_is;
|
|||
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum VarSource {
|
||||
Shell(String),
|
||||
Function(fn() -> Result<PrimVal>),
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct PollScriptVar {
|
||||
pub name: VarName,
|
||||
pub command: String,
|
||||
pub command: VarSource,
|
||||
pub interval: std::time::Duration,
|
||||
}
|
||||
|
||||
impl PollScriptVar {
|
||||
pub fn run_once(&self) -> Result<PrimVal> {
|
||||
run_command(&self.command)
|
||||
match &self.command {
|
||||
VarSource::Shell(x) => run_command(x),
|
||||
VarSource::Function(x) => x(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,9 +49,12 @@ impl ScriptVar {
|
|||
|
||||
pub fn initial_value(&self) -> Result<PrimVal> {
|
||||
match self {
|
||||
ScriptVar::Poll(x) => {
|
||||
run_command(&x.command).with_context(|| format!("Failed to compute initial value for {}", &self.name()))
|
||||
}
|
||||
ScriptVar::Poll(x) => match &x.command {
|
||||
VarSource::Function(f) => f().with_context(|| format!("Failed to compute initial value for {}", &self.name())),
|
||||
VarSource::Shell(f) => {
|
||||
run_command(&f).with_context(|| format!("Failed to compute initial value for {}", &self.name()))
|
||||
}
|
||||
},
|
||||
ScriptVar::Tail(_) => Ok(PrimVal::from_string(String::new())),
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +66,7 @@ impl ScriptVar {
|
|||
let command = xml.only_child()?.as_text()?.text();
|
||||
if let Ok(interval) = xml.attr("interval") {
|
||||
let interval = util::parse_duration(&interval)?;
|
||||
Ok(ScriptVar::Poll(PollScriptVar { name, command, interval }))
|
||||
Ok(ScriptVar::Poll(PollScriptVar { name, command: crate::config::VarSource::Shell(command), interval }))
|
||||
} else {
|
||||
Ok(ScriptVar::Tail(TailScriptVar { name, command }))
|
||||
}
|
||||
|
|
153
src/config/system_stats.rs
Normal file
153
src/config/system_stats.rs
Normal file
|
@ -0,0 +1,153 @@
|
|||
use crate::util::IterAverage;
|
||||
use anyhow::*;
|
||||
use itertools::Itertools;
|
||||
use lazy_static::lazy_static;
|
||||
use std::{fs::read_to_string, sync::Mutex};
|
||||
use sysinfo::{ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessorExt, System, SystemExt};
|
||||
|
||||
lazy_static! {
|
||||
static ref SYSTEM: Mutex<System> = Mutex::new(System::new());
|
||||
}
|
||||
|
||||
pub fn disk() -> String {
|
||||
let mut c = SYSTEM.lock().unwrap();
|
||||
c.refresh_disks_list();
|
||||
|
||||
format!(
|
||||
"{{ {} }}",
|
||||
c.get_disks()
|
||||
.iter()
|
||||
.map(|c| format!(
|
||||
r#""{}": {{"name": {:?}, "total": {}, "free": {}}}"#,
|
||||
c.get_mount_point().display(),
|
||||
c.get_name(),
|
||||
c.get_total_space(),
|
||||
c.get_available_space(),
|
||||
))
|
||||
.join(",")
|
||||
)
|
||||
}
|
||||
|
||||
pub fn ram() -> f32 {
|
||||
let mut c = SYSTEM.lock().unwrap();
|
||||
c.refresh_memory();
|
||||
(c.get_used_memory() as f32 + c.get_used_swap() as f32) / 1_000_000f32
|
||||
}
|
||||
|
||||
pub fn cores() -> String {
|
||||
let mut c = SYSTEM.lock().unwrap();
|
||||
c.refresh_components_list();
|
||||
c.refresh_components();
|
||||
format!(
|
||||
"{{ {} }}",
|
||||
c.get_components()
|
||||
.iter()
|
||||
.map(|c| format!(r#""{}": {}"#, c.get_label().to_uppercase().replace(" ", "_"), c.get_temperature()))
|
||||
.join(",")
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_avg_cpu_usage() -> String {
|
||||
let mut c = SYSTEM.lock().unwrap();
|
||||
c.refresh_cpu();
|
||||
let processors = c.get_processors();
|
||||
format!(
|
||||
r#"{{ "cores": [{}], "avg": {} }}"#,
|
||||
processors
|
||||
.iter()
|
||||
.map(|a| format!(r#"{{"core": "{}", "freq": {}, "usage": {}}}"#, a.get_name(), a.get_frequency(), a.get_cpu_usage()))
|
||||
.join(","),
|
||||
processors.iter().map(|a| a.get_cpu_usage()).avg()
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn get_battery_capacity() -> Result<String> {
|
||||
use regex::Regex;
|
||||
let capacity = String::from_utf8(
|
||||
std::process::Command::new("pmset")
|
||||
.args(&["-g", "batt"])
|
||||
.output()
|
||||
.context("\nError while getting the battery value on macos, with `pmset`: ")?
|
||||
.stdout,
|
||||
)?;
|
||||
|
||||
// Example output of that command:
|
||||
// Now drawing from 'Battery Power'
|
||||
//-InternalBattery-0 (id=11403363) 100%; discharging; (no estimate) present: true
|
||||
let regex = Regex::new(r"[0-9]*%")?;
|
||||
let mut number = regex.captures(&capacity).unwrap().get(0).unwrap().as_str().to_string();
|
||||
|
||||
// Removes the % at the end
|
||||
number.pop();
|
||||
Ok(format!(
|
||||
"{{ \"BAT0\": {{ \"capacity\": \"{}\", \"status\": \"{}\" }}}}",
|
||||
number,
|
||||
capacity.split(";").collect::<Vec<&str>>()[1]
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn get_battery_capacity() -> Result<String> {
|
||||
let mut current = 0_f64;
|
||||
let mut total = 0_f64;
|
||||
let mut json = String::from('{');
|
||||
for i in
|
||||
std::path::Path::new("/sys/class/power_supply").read_dir().context("Couldn't read /sys/class/power_supply directory")?
|
||||
{
|
||||
let i = i?.path();
|
||||
if i.is_dir() {
|
||||
// some ugly hack because if let Some(a) = a && Some(b) = b doesn't work yet
|
||||
if let (Ok(o), Ok(s)) = (read_to_string(i.join("capacity")), read_to_string(i.join("status"))) {
|
||||
json.push_str(&format!(
|
||||
r#"{:?}: {{ "status": "{}", "capacity": {} }},"#,
|
||||
i.file_name().context("couldn't convert file name to rust string")?,
|
||||
s.replace("\n", ""),
|
||||
o.replace("\n", "")
|
||||
));
|
||||
if let (Ok(t), Ok(c), Ok(v)) = (
|
||||
read_to_string(i.join("charge_full")),
|
||||
read_to_string(i.join("charge_now")),
|
||||
read_to_string(i.join("voltage_now")),
|
||||
) {
|
||||
// (uAh / 1000000) * U = p and that / one million so that we have microwatt
|
||||
current +=
|
||||
((c.replace("\n", "").parse::<f64>()? / 1000000_f64) * v.replace("\n", "").parse::<f64>()?) / 1000000_f64;
|
||||
total +=
|
||||
((t.replace("\n", "").parse::<f64>()? / 1000000_f64) * v.replace("\n", "").parse::<f64>()?) / 1000000_f64;
|
||||
} else if let (Ok(t), Ok(c)) = (read_to_string(i.join("energy_full")), read_to_string(i.join("energy_now"))) {
|
||||
current += c.replace("\n", "").parse::<f64>()?;
|
||||
total += t.replace("\n", "").parse::<f64>()?;
|
||||
} else {
|
||||
log::warn!(
|
||||
"Failed to get/calculate uWh: the total_avg value of the battery magic var will probably be a garbage \
|
||||
value that can not be trusted."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
json.pop();
|
||||
json.push_str(&format!(r#", "total_avg": {:.1}}}"#, (current / total) * 100_f64));
|
||||
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub fn get_battery_capacity() -> Result<u8> {
|
||||
anyhow!("eww doesn't support your OS for getting the battery capacity")
|
||||
}
|
||||
|
||||
pub fn net() -> String {
|
||||
let mut c = SYSTEM.lock().unwrap();
|
||||
let interfaces = format!(
|
||||
"{{ {} }}",
|
||||
&c.get_networks()
|
||||
.iter()
|
||||
.map(|a| format!(r#""{}": {{ "NET_UP": {}, "NET_DOWN": {} }}"#, a.0, a.1.get_transmitted(), a.1.get_received()))
|
||||
.join(","),
|
||||
);
|
||||
c.refresh_networks_list();
|
||||
interfaces
|
||||
}
|
12
src/opts.rs
12
src/opts.rs
|
@ -108,9 +108,13 @@ pub enum ActionWithServer {
|
|||
#[structopt(name = "close-all", alias = "ca")]
|
||||
CloseAll,
|
||||
|
||||
/// Print the current eww-state
|
||||
/// Prints the variables used in all currently open window
|
||||
#[structopt(name = "state")]
|
||||
ShowState,
|
||||
ShowState {
|
||||
/// Shows all variables, including not currently used ones
|
||||
#[structopt(short, long)]
|
||||
all: bool,
|
||||
},
|
||||
|
||||
/// Print the names of all configured windows. Windows with a * in front of them are currently opened.
|
||||
#[structopt(name = "windows")]
|
||||
|
@ -175,7 +179,9 @@ impl ActionWithServer {
|
|||
}
|
||||
ActionWithServer::Reload => return with_response_channel(app::DaemonCommand::ReloadConfigAndCss),
|
||||
ActionWithServer::ShowWindows => return with_response_channel(app::DaemonCommand::PrintWindows),
|
||||
ActionWithServer::ShowState => return with_response_channel(app::DaemonCommand::PrintState),
|
||||
ActionWithServer::ShowState { all } => {
|
||||
return with_response_channel(|sender| app::DaemonCommand::PrintState { all, sender })
|
||||
}
|
||||
ActionWithServer::ShowDebug => return with_response_channel(app::DaemonCommand::PrintDebug),
|
||||
};
|
||||
(command, None)
|
||||
|
|
17
src/util.rs
17
src/util.rs
|
@ -112,6 +112,23 @@ pub fn parse_duration(s: &str) -> Result<std::time::Duration> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait IterAverage {
|
||||
fn avg(self) -> f32;
|
||||
}
|
||||
|
||||
impl<I: Iterator<Item = f32>> IterAverage for I {
|
||||
fn avg(self) -> f32 {
|
||||
let mut total = 0f32;
|
||||
let mut cnt = 0f32;
|
||||
for value in self {
|
||||
total += value;
|
||||
cnt += 1f32;
|
||||
}
|
||||
total / cnt
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace all env-var references of the format `"something ${foo}"` in a string
|
||||
/// by the actual env-variables. If the env-var isn't found, will replace the
|
||||
/// reference with an empty string.
|
||||
|
|
|
@ -65,6 +65,23 @@ impl From<i32> for PrimVal {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<u32> for PrimVal {
|
||||
fn from(s: u32) -> Self {
|
||||
PrimVal(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for PrimVal {
|
||||
fn from(s: f32) -> Self {
|
||||
PrimVal(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for PrimVal {
|
||||
fn from(s: u8) -> Self {
|
||||
PrimVal(s.to_string())
|
||||
}
|
||||
}
|
||||
impl From<f64> for PrimVal {
|
||||
fn from(s: f64) -> Self {
|
||||
PrimVal(s.to_string())
|
||||
|
|
Loading…
Add table
Reference in a new issue