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
|
uses: denoland/setup-deno@main
|
||||||
with:
|
with:
|
||||||
deno-version: "v1.x"
|
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
|
# Build & deploy
|
||||||
- name: shalzz/zola-deploy-action
|
- name: shalzz/zola-deploy-action
|
||||||
|
|
133
Cargo.lock
generated
133
Cargo.lock
generated
|
@ -71,7 +71,7 @@ checksum = "db134ba52475c060f3329a8ef0f8786d6b872ed01515d4b79c162e5798da1340"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -227,6 +227,12 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-channel"
|
name = "crossbeam-channel"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
@ -237,6 +243,30 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"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]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
|
@ -255,7 +285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d"
|
checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -277,7 +307,7 @@ dependencies = [
|
||||||
"convert_case",
|
"convert_case",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -286,6 +316,12 @@ version = "0.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
|
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "doc-comment"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyn-clone"
|
name = "dyn-clone"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
@ -353,6 +389,7 @@ dependencies = [
|
||||||
"simple-signal",
|
"simple-signal",
|
||||||
"smart-default",
|
"smart-default",
|
||||||
"structopt",
|
"structopt",
|
||||||
|
"sysinfo",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
@ -370,7 +407,7 @@ dependencies = [
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -467,7 +504,7 @@ dependencies = [
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -693,7 +730,7 @@ dependencies = [
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -981,6 +1018,15 @@ version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.7.11"
|
version = "0.7.11"
|
||||||
|
@ -1273,7 +1319,7 @@ dependencies = [
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1349,7 +1395,7 @@ dependencies = [
|
||||||
"proc-macro-error-attr",
|
"proc-macro-error-attr",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1464,19 +1510,44 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "rayon"
|
||||||
version = "0.2.7"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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 = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.5.2"
|
version = "1.5.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1efb2352a0f4d4b128f734b5c44c79ff80117351138733f12f982fe3e2b13343"
|
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -1485,9 +1556,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.24"
|
version = "0.6.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00efb87459ba4f6fb2169d20f68565555688e1250ee6825cdf6254f8b48fafb2"
|
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roxmltree"
|
name = "roxmltree"
|
||||||
|
@ -1536,7 +1607,7 @@ checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1595,7 +1666,7 @@ checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1631,7 +1702,7 @@ dependencies = [
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1649,7 +1720,7 @@ dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1665,9 +1736,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.71"
|
version = "1.0.72"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373"
|
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
|
@ -1683,6 +1754,22 @@ dependencies = [
|
||||||
"unicode-xid 0.0.4",
|
"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]]
|
[[package]]
|
||||||
name = "system-deps"
|
name = "system-deps"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -1739,7 +1826,7 @@ checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1770,7 +1857,7 @@ checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.71",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -60,6 +60,7 @@ futures-core = "0.3"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
tokio-util = "0.6"
|
tokio-util = "0.6"
|
||||||
|
|
||||||
|
sysinfo = "0.16.1"
|
||||||
|
|
||||||
nom = "6.1"
|
nom = "6.1"
|
||||||
dyn-clone = "1.0"
|
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"
|
slug = "widget documentation"
|
||||||
weight = 3
|
weight = 3
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
|
22
gen-docs.ts
22
gen-docs.ts
|
@ -12,6 +12,18 @@ interface Widget {
|
||||||
isVisible: boolean;
|
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> {
|
function parseVars(code: string): Record<string, string> {
|
||||||
const VAR_PATTERN = /^.*\/\/+ *@var +(.*?) +- +(.*)$/;
|
const VAR_PATTERN = /^.*\/\/+ *@var +(.*?) +- +(.*)$/;
|
||||||
const vars: Record<string, string> = {};
|
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) => printWidget(x))
|
||||||
.map((x) => x.replace(/\$\w+/g, (x) => vars[x.replace("$", "")]))
|
.map((x) => x.replace(/\$\w+/g, (x) => vars[x.replace("$", "")]))
|
||||||
.join("\n\n");
|
.join("\n\n");
|
||||||
console.log(output);
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
function printWidget(widget: Widget) {
|
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 run --allow-read gen-docs.ts ./src/widgets/widget_definitions.ts 2> /dev/null
|
||||||
Deno.readTextFile(Deno.args[0]).then(data => {
|
Deno.readTextFile(Deno.args[0]).then(data => {
|
||||||
const vars = parseVars(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 => {
|
}).catch(err => {
|
||||||
return console.error(err);
|
return console.error(err);
|
||||||
})
|
})
|
||||||
|
|
18
src/app.rs
18
src/app.rs
|
@ -60,7 +60,10 @@ pub enum DaemonCommand {
|
||||||
},
|
},
|
||||||
KillServer,
|
KillServer,
|
||||||
CloseAll,
|
CloseAll,
|
||||||
PrintState(DaemonResponseSender),
|
PrintState {
|
||||||
|
all: bool,
|
||||||
|
sender: DaemonResponseSender,
|
||||||
|
},
|
||||||
PrintDebug(DaemonResponseSender),
|
PrintDebug(DaemonResponseSender),
|
||||||
PrintWindows(DaemonResponseSender),
|
PrintWindows(DaemonResponseSender),
|
||||||
}
|
}
|
||||||
|
@ -157,9 +160,15 @@ impl App {
|
||||||
let result = self.close_window(&window_name);
|
let result = self.close_window(&window_name);
|
||||||
respond_with_error(sender, result)?;
|
respond_with_error(sender, result)?;
|
||||||
}
|
}
|
||||||
DaemonCommand::PrintState(sender) => {
|
DaemonCommand::PrintState { all, sender } => {
|
||||||
let output =
|
let vars = self.eww_state.get_variables().iter();
|
||||||
self.eww_state.get_variables().iter().map(|(key, value)| format!("{}: {}", key, value)).join("\n");
|
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")?
|
sender.send(DaemonResponse::Success(output)).context("sending response from main thread")?
|
||||||
}
|
}
|
||||||
DaemonCommand::PrintWindows(sender) => {
|
DaemonCommand::PrintWindows(sender) => {
|
||||||
|
@ -219,7 +228,6 @@ impl App {
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// remove and close existing window with the same name
|
// remove and close existing window with the same name
|
||||||
let _ = self.close_window(window_name);
|
let _ = self.close_window(window_name);
|
||||||
|
|
||||||
log::info!("Opening window {}", window_name);
|
log::info!("Opening window {}", window_name);
|
||||||
|
|
||||||
let mut window_def = self.eww_config.get_window(window_name)?.clone();
|
let mut window_def = self.eww_config.get_window(window_name)?.clone();
|
||||||
|
|
|
@ -90,7 +90,6 @@ impl RawEwwConfig {
|
||||||
included_path.display()
|
included_path.display()
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
for included_config in includes {
|
for included_config in includes {
|
||||||
for conflict in util::extend_safe(&mut eww_config.widgets, included_config.widgets) {
|
for conflict in util::extend_safe(&mut eww_config.widgets, included_config.widgets) {
|
||||||
log_conflict("widget", &conflict, &included_config.filepath)
|
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()),
|
_ => 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))
|
Ok((normal_vars, script_vars))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +284,6 @@ mod test {
|
||||||
assert_eq!(merged_config.widgets.len(), 2);
|
assert_eq!(merged_config.widgets.len(), 2);
|
||||||
assert_eq!(merged_config.windows.len(), 2);
|
assert_eq!(merged_config.windows.len(), 2);
|
||||||
assert_eq!(merged_config.initial_variables.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 element;
|
||||||
pub mod eww_config;
|
pub mod eww_config;
|
||||||
|
pub mod inbuilt;
|
||||||
pub mod script_var;
|
pub mod script_var;
|
||||||
|
pub mod system_stats;
|
||||||
pub mod window_definition;
|
pub mod window_definition;
|
||||||
pub mod window_geometry;
|
pub mod window_geometry;
|
||||||
pub mod xml_ext;
|
pub mod xml_ext;
|
||||||
|
|
|
@ -6,16 +6,24 @@ use crate::ensure_xml_tag_is;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum VarSource {
|
||||||
|
Shell(String),
|
||||||
|
Function(fn() -> Result<PrimVal>),
|
||||||
|
}
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct PollScriptVar {
|
pub struct PollScriptVar {
|
||||||
pub name: VarName,
|
pub name: VarName,
|
||||||
pub command: String,
|
pub command: VarSource,
|
||||||
pub interval: std::time::Duration,
|
pub interval: std::time::Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PollScriptVar {
|
impl PollScriptVar {
|
||||||
pub fn run_once(&self) -> Result<PrimVal> {
|
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> {
|
pub fn initial_value(&self) -> Result<PrimVal> {
|
||||||
match self {
|
match self {
|
||||||
ScriptVar::Poll(x) => {
|
ScriptVar::Poll(x) => match &x.command {
|
||||||
run_command(&x.command).with_context(|| format!("Failed to compute initial value for {}", &self.name()))
|
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())),
|
ScriptVar::Tail(_) => Ok(PrimVal::from_string(String::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +66,7 @@ impl ScriptVar {
|
||||||
let command = xml.only_child()?.as_text()?.text();
|
let command = xml.only_child()?.as_text()?.text();
|
||||||
if let Ok(interval) = xml.attr("interval") {
|
if let Ok(interval) = xml.attr("interval") {
|
||||||
let interval = util::parse_duration(&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 {
|
} else {
|
||||||
Ok(ScriptVar::Tail(TailScriptVar { name, command }))
|
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")]
|
#[structopt(name = "close-all", alias = "ca")]
|
||||||
CloseAll,
|
CloseAll,
|
||||||
|
|
||||||
/// Print the current eww-state
|
/// Prints the variables used in all currently open window
|
||||||
#[structopt(name = "state")]
|
#[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.
|
/// Print the names of all configured windows. Windows with a * in front of them are currently opened.
|
||||||
#[structopt(name = "windows")]
|
#[structopt(name = "windows")]
|
||||||
|
@ -175,7 +179,9 @@ impl ActionWithServer {
|
||||||
}
|
}
|
||||||
ActionWithServer::Reload => return with_response_channel(app::DaemonCommand::ReloadConfigAndCss),
|
ActionWithServer::Reload => return with_response_channel(app::DaemonCommand::ReloadConfigAndCss),
|
||||||
ActionWithServer::ShowWindows => return with_response_channel(app::DaemonCommand::PrintWindows),
|
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),
|
ActionWithServer::ShowDebug => return with_response_channel(app::DaemonCommand::PrintDebug),
|
||||||
};
|
};
|
||||||
(command, None)
|
(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
|
/// 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
|
/// by the actual env-variables. If the env-var isn't found, will replace the
|
||||||
/// reference with an empty string.
|
/// 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 {
|
impl From<f64> for PrimVal {
|
||||||
fn from(s: f64) -> Self {
|
fn from(s: f64) -> Self {
|
||||||
PrimVal(s.to_string())
|
PrimVal(s.to_string())
|
||||||
|
|
Loading…
Add table
Reference in a new issue