桌面应用【免费下载链接】ewwElKowars wacky widgets项目地址https://gitcode.com/gh_mirrors/ew/eww点击查看免费下载导读本文全面讲解 ewwElKowars wacky widgets自带的简单表达式语言——simplexpr。它是 Yuck 配置语法中内置的一套微型动态求值引擎让你在{ ... }表达式块和${ ... }字符串插值中完成条件分支、数学计算、正则匹配、JSON 结构取值以及调用丰富的内置函数。读完本文你将掌握 simplexpr 的全部运算符、函数与源码级实现细节并能在自己的 bar / 桌面组件配置中写出精确、健壮的动态表达式。本文主体内容基于 docs/src/expression_language.md实现细节来自仓库内的simplexprcrate 源码crates/simplexpr与示例配置examples/eww-bar/eww.yuck。表达式语言是什么Yuck 内置了一个轻量级表达式语言实现于独立的simplexprcrate见 crates/simplexpr/Cargo.toml它允许你对数据执行多种操作根据特定条件展示不同的值进行数学运算甚至访问 JSON 结构内部的值。表达式可以放置在配置中任意位置的{ ... }块内也可以放进字符串的插值块foo ${ ... } bar中。在 eww 中几乎所有动态属性如 widget 的:class、按钮文本、deflisten/defpoll变量的消费处都支持直接书写表达式——从源码结构看Yuck 配置解析器通过ast_optional::SimplExpr/ast_required::SimplExpr将属性值解析为表达式 AST见 crates/yuck/src/config/attributes.rs例如defpoll的run-while就是一个SimplExpr见 crates/yuck/src/config/script_var_definition.rs。一个完整示例原文档给出了下面这个典型用法同时用到了数学运算、条件表达式和字符串插值(box Some math: ${12 foo * 10} (button :class {button_active ? active : inactive} :onclick toggle_thing {button_active ? disable : enable}))其中{button_active ? active : inactive}根据变量button_active的真假在两个字符串间切换${12 foo * 10}则在字符串内部完成一次带变量参与的算术求值。支持的运算符与特性simplexpr 当前支持以下全部特性数学运算、-、*、/、%五个二元运算符。值得注意的是的行为是动态的从 eval.rs 的实现看如果左右两侧都能解析为f64则做数值加法否则回退为字符串拼接——这意味着foo 12.4会得到foo12.4这一行为在解析器测试中也有对应用例parser/mod.rs。-、*、/、%则严格要求数值运算通过as_f64转换。比较运算、!、、、、。其中/!的底层基于DynVal的相等性实现如果两边都能转为f64则按数值比较允许1 1.0成立见 dynval.rs、等关系运算则按f64数值比较。布尔运算||或、与、!非。与||都是惰性求值的求值器只在需要时才计算右侧操作数见 eval.rs配套测试lazy_evaluation_and/lazy_evaluation_or验证了false null.test与true || null.test不会因右侧的非法访问而报错见 eval.rs。这意味着你可以在右侧放心书写可能失败的表达式。正则匹配运算符~用于正则匹配采用 Rust 正则风格。需要说明的是虽然原文档对操作数方向的描述存在歧义但根据求值实现eval.rs与文档自带示例实际语义是右侧为正则表达式模式、左侧为被匹配的字符串workspace.name ~ ^special:.$ ; 判断 workspace.name 是否以 special: 开头该运算符返回布尔值。正则表达式非法时会报Invalid regex错误。Elvis 运算符?:类似于空值兜底如果左侧是空字符串或 JSONnull则整个表达式求值为右侧否则求值为左侧。它同样是惰性的——只有当左侧为空时才求值右侧eval.rs测试lazy_evaluation_elvis验证了test?: null.test返回test而不会触碰右侧。典型的恢复用法来自 lexer 测试快照safe_interpolation${ { key: value }.key1?.key2 ?: Recovery }当链式安全访问得到null时兜底为字符串Recovery。安全访问运算符?.与?.[index]用于对可能为空的值做安全的 JSON 索引如果左侧是空字符串或 JSONnull直接返回null不再进行索引否则尝试索引。注意索引空 JSON 字符串即值为会直接报错——因为空字符串无法被解析成 JSON 值见 eval.rs 与配套测试safe_access_to_empty_json_string如果左侧存在但不是对象或数组例如Number或String仍然会产生错误。测试safe_access_index_to_non_indexable验证了32?.[1]会报CannotIndex错误。条件表达式condition ? value : other value从语法定义看三元条件是最低优先级level 7的右结合运算符simplexpr_parser.lalrpop因此它可以安全地嵌套在算术表达式外层。字面量与变量引用支持数字、字符串、布尔值与变量引用12、hi、true、some_variable。字符串字面量支持三种引号、与反引号见 lexer.rs并支持\转义。词法规则中标识符形如[a-zA-Z_][a-zA-Z0-9_-]*数字形如[-]?(?:[0-9][.])?[0-9]lexer.rs。此外还支持;开头的行注释。变量引用在求值前会被替换为变量的当前值resolve_refs见 eval.rs如果引用了不存在的变量错误信息会通过编辑距离算法strsim提示最相似的候选变量名。JSON 访问object.field array[12] object[field]JSON 访问要求对象/数组值本身来自一个包含合法 JSON 字符串的变量。求值时通过serde_json把值解析为 JSON 值再按数组索引或对象键取值eval.rs对象键既支持字符串也支持数字索引会尝试把索引转成字符串去查键。一个经典的实战例子来自内置示例栏examples/eww-bar/eww.yuck(metric :label :value {EWW_RAM.used_mem_perc} :onchange ) (metric :label :value {round((1 - (EWW_DISK[/].free / EWW_DISK[/].total)) * 100, 0)} :onchange )这里EWW_RAM、EWW_DISK是 eww 提供的魔法变量其值由 crates/eww/src/config/system_stats.rs 生成EWW_RAM是一个包含used_mem_perc、total_mem等字段的 JSON 对象system_stats.rsEWW_DISK则是以挂载点为键的 JSON 对象每个挂载点下含total、free、used、used_perc等字段system_stats.rs。因此EWW_RAM.used_mem_perc直接点号取字段、EWW_DISK[/].free先按挂载点字符串取键再取字段。字符串插值在双引号字符串内${ ... }会求值其中的表达式并把结果嵌入字符串Some math: ${12 foo * 10} {music ! ? ${music} : }字符串插值支持嵌套插值块内可以再出现字符串插值词法器通过花括号层级计数来定位插值块的结束位置lexer.rs相关行为有快照测试interpolation_nested、json_in_interpolation、empty_interpolation等佐证。运算符优先级总览根据 simplexpr_parser.lalrpop 的优先级声明从高到低为优先级运算符结合性1函数调用f(...)、JSON 访问./[ ]/?./?.[]—后缀2一元!、-右3*/%左4-左5!~左6||?:左7三元? :右字面量、变量引用、括号、JSON 数组[...]与 JSON 对象{...}属于原子表达式。解析器测试覆盖了1 true ? 2 : 5、(1 2) * 2等组合用例来锁定这些优先级行为parser/mod.rs。内置函数详解以下函数均由 eval.rs 中的call_expr_function实现参数个数不符会报WrongArgCount错误函数名不存在会报UnknownFunction。数学函数函数说明备注round(number, decimal_digits)将数字四舍五入到指定小数位底层用format!({:.1$}, ...)实现结果是字符串形式floor(number)向下取整到最近整数ceil(number)向上取整到最近整数sin(n)/cos(n)/tan(n)/cot(n)三角函数参数单位为弧度cot实现为1.0 / tan(n)min(a, b)/max(a, b)取两数中较小 / 较大者powi(num, n)幂运算n必须是i32类型powf(num, n)幂运算num、n与返回值均为f64log(num, n)以n为底、对num求对数参数与返回值为f64degtorad(number)角度转弧度radtodeg(number)弧度转角度字符串与正则函数函数说明replace(string, regex, replacement)将字符串中匹配给定正则的所有片段替换为 replacementsearch(string, regex)在字符串中搜索正则的所有匹配返回由匹配文本组成的数组matches(string, regex)判断字符串是否匹配给定正则返回布尔值captures(string, regex)获取正则的所有捕获组返回数组每个匹配对应一组捕获数组套数组strlength(value)返回字符串长度substring(string, start, length)从start索引开始截取指定length的子串。实现按 Unicode 字符chars()截取start与length为负数时按 0 处理见 eval.rsarraylength(value)返回 JSON 数组长度objectlength(value)返回 JSON 对象条目数正则一律采用 Rust 的regexcrate 语法。jq 函数jq(value, jq_filter_string)对一个 JSON 值运行 jq 风格的过滤器。eww 内部通过jaqcrate 实现依赖声明见 crates/simplexpr/Cargo.toml编译后的过滤器会做 LRU 缓存容量 10见 eval.rs。jq([7,8,9], .[0]) ; - 7 jq([ \foo\ ], .[0]) ; - foo带 JSON 引号的形式jq(value, jq_filter_string, args)第三个参数模拟 jq 命令行标志目前支持r等价于 jq 的--raw-output当结果为字符串时不输出 JSON 转义引号其他非法标志会被静默忽略。配套测试验证了这几种形态eval.rsjq([ \foo\ ], .[0], r)返回foo不带r或传非法参数则返回foo带引号。环境与系统函数函数说明get_env(string)读取指定环境变量未设置时返回空字符串eval.rsformattime(unix_timestamp, format_str, timezone)按给定时区把 UNIX 时间戳格式化为时间字符串时区使用chrono-tz的时区名如Asia/Shanghai格式化指令遵循chrono的 strftime 规范formattime(unix_timestamp, format_str)同上但不指定时区使用系统本地时区eval.rsformattime的底层实现还引入了本地化格式串通过get_locale()指定的语言环境进行渲染见 crates/eww_shared_util/src/locale.rs这也是chrono启用unstable-localesfeature 的原因crates/simplexpr/Cargo.toml。时间戳非法会报Invalid UNIX timestamp格式串非法会报Invalid time formatting string。函数说明formatbytes(bytes, short, format_mode)把字节数格式化为人类可读形式返回字符串formatbytes的参数bytesi64字节数支持负数负数会以-前缀输出short布尔值为true时输出紧凑版本默认falseformat_modeiec如1.0 GiB默认或si如1.2 GB其他值会报ByteFormatModeError。该函数还支持 1 参数formatbytes(bytes)与 2 参数formatbytes(bytes, short)的省略形式eval.rs。运行时模型DynVal 与求值过程理解 simplexpr 的运行时模型有助于排查表达式问题。所有表达式的求值结果统一包装为DynVal类型dynval.rs其本质是一个字符串 源文件位置 Span数值、布尔在需要时通过as_f64/as_i32/as_i64/as_bool即时解析失败时产生带类型目标的ConversionErrorJSON 值通过as_json_value/as_json_array/as_json_object在需要时解析为serde_json::Value因此类型是上下文相关的动态转换同一个值在不同运算符下可以按数字、字符串或 JSON 解释。求值过程分为两步parser/mod.rs 与 eval.rs解析parse_string驱动 LALRPOP 生成的解析器把表达式文本转成SimplExprAST词法层面支持、、三种引号、字符串插值与注释求值SimplExpr::eval递归求值变量通过HashMapVarName, DynVal查表替换所有错误都会携带 Span最终以带位置信息的诊断呈现见 error.rs 的ParseError与EvalError::Spanned。AST 定义中的references_var/collect_var_refs方法还会被上层用于依赖追踪——从源码结构看这使得 eww 能精确知道某条表达式依赖哪些变量从而在变量更新时只重算受影响的 widget。实战场景速查以下模式覆盖了表达式语言最常用的几种场景可直接套用; 1. 根据条件切换 class / 文案 (button :class {button_active ? active : inactive} {button_active ? disable : enable}) ; 2. 字符串插值内做运算与变量拼接 CPU: ${EWW_CPU.avg}% RAM: ${EWW_RAM.used_mem_perc}% ; 3. JSON 嵌套访问 数值计算磁盘使用率百分比保留整数 {round((1 - (EWW_DISK[/].free / EWW_DISK[/].total)) * 100, 0)} ; 4. 空值兜底 {player_title ?: Nothing playing} ; 5. 正则匹配分支 {workspace.name ~ ^special:.$ ? special : normal} ; 6. 正则捕获 jq 取值 {jq(captures(2024-01-15, ^([0-9]{4})), .[0][0])} ; 7. 时间与字节格式化 {formattime(EWW_TIME, %H:%M:%S, Asia/Shanghai)} {formatbytes(EWW_DISK[/].used, false, iec)}说明EWW_TIME、EWW_RAM、EWW_CPU、EWW_DISK均为 eww 内置魔法变量见 docs/src/magic-vars.md其中EWW_TIME每秒刷新其余更新变量的刷新间隔为 2 秒。总结simplexpr 虽然小巧但能力完整从四则运算、比较与布尔逻辑到正则、条件、空值兜底、安全访问再到 JSON 索引、jq 过滤以及 20 余个内置函数足以覆盖桌面组件配置中绝大多数的动态渲染需求。它的实现全部集中在 crates/simplexpr/src 目录下词法 lexer.rs、语法 simplexpr_parser.lalrpop、求值 eval.rs并配有丰富的解析快照与求值单测如 eval.rs 的evals_as系列可直接作为你验证表达式行为时的参照标准。赞分享桌面应用【免费下载链接】ewwElKowars wacky widgets项目地址https://gitcode.com/gh_mirrors/ew/eww点击查看免费下载相关推荐eww表达式语言simplexpr实战教程20内置函数玩转条件判断、数学运算与JSON数据eww表达式语言simplexpr实战教程20内置函数玩转条件判断、数学运算与JSON数据 eww ElKowars Wacky Widgets是一个桌面应用GraphGen核心功能详解从知识图谱构建到智能问答对生成的完整流程GraphGen核心功能详解从知识图谱构建到智能问答对生成的完整流程 GraphGen是一个基于知识图谱的数据合成框架它能通过构建细粒度知识图谱来增强大语言Metabase case 表达式完全指南条件逻辑、数据分桶与聚合实战Metabase case 表达式完全指南条件逻辑、数据分桶与聚合实战 case 别名 if 是 Metabase 自定义表达式Custom Expre数据分析数据可视化后端数据库客户端企业应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
