From 6ee166707fb644d501a6d9151a491d07916ca4ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?W=C3=B6lfchen?= Date: Fri, 27 Dec 2024 22:49:28 +0000 Subject: [PATCH] feat: add `raw-output` for `jq` (#1199) * feat: add raw-output arg to jq Co-authored-by: Roman Hargrave * test: add some test cases for jq raw output * refactor: improve run_jaq_function * docs: document changes --------- Co-authored-by: Roman Hargrave --- CHANGELOG.md | 1 + crates/simplexpr/src/eval.rs | 30 ++++++++++++++++++++---------- docs/src/expression_language.md | 17 ++++++++++------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ee0298b..41903683 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ All notable changes to eww will be listed here, starting at changes since versio ### Features - Add OnDemand support for focusable on wayland (By: GallowsDove) +- Add jq `raw-output` support (By: RomanHargrave) - Update rust toolchain to 1.81.0 (By: w-lfchen) - Add `:fill-svg` and `:preserve-aspect-ratio` properties to images (By: hypernova7, w-lfchen) - Add `:truncate` property to labels, disabled by default (except in cases where truncation would be enabled in version `0.5.0` and before) (By: Rayzeq). diff --git a/crates/simplexpr/src/eval.rs b/crates/simplexpr/src/eval.rs index 545f9567..d75c2c49 100644 --- a/crates/simplexpr/src/eval.rs +++ b/crates/simplexpr/src/eval.rs @@ -472,7 +472,9 @@ fn call_expr_function(name: &str, args: Vec) -> Result Err(EvalError::WrongArgCount(name.to_string())), }, "jq" => match args.as_slice() { - [json, code] => run_jaq_function(json.as_json_value()?, code.as_string()?) + [json, code] => run_jaq_function(json.as_json_value()?, code.as_string()?, "") + .map_err(|e| EvalError::Spanned(code.span(), Box::new(e))), + [json, code, args] => run_jaq_function(json.as_json_value()?, code.as_string()?, &args.as_string()?) .map_err(|e| EvalError::Spanned(code.span(), Box::new(e))), _ => Err(EvalError::WrongArgCount(name.to_string())), }, @@ -522,16 +524,20 @@ fn prepare_jaq_filter(code: String) -> Result, EvalEr Ok(Arc::new(filter)) } -fn run_jaq_function(json: serde_json::Value, code: String) -> Result { - let filter: Arc = prepare_jaq_filter(code)?; - let inputs = jaq_interpret::RcIter::new(std::iter::empty()); - let out = filter - .run((jaq_interpret::Ctx::new([], &inputs), jaq_interpret::Val::from(json))) - .map(|x| x.map(Into::::into)) - .map(|x| x.map(|x| DynVal::from_string(serde_json::to_string(&x).unwrap()))) +fn run_jaq_function(json: serde_json::Value, code: String, args: &str) -> Result { + use jaq_interpret::{Ctx, RcIter, Val}; + prepare_jaq_filter(code)? + .run((Ctx::new([], &RcIter::new(std::iter::empty())), Val::from(json))) + .map(|r| r.map(Into::::into)) + .map(|x| { + x.map(|val| match (args, val) { + ("r", serde_json::Value::String(s)) => DynVal::from_string(s), + // invalid arguments are silently ignored + (_, v) => DynVal::from_string(serde_json::to_string(&v).unwrap()), + }) + }) .collect::>() - .map_err(|e| EvalError::JaqError(e.to_string()))?; - Ok(out) + .map_err(|e| EvalError::JaqError(e.to_string())) } #[cfg(test)] @@ -592,5 +598,9 @@ mod tests { lazy_evaluation_or(r#"true || "null".test"#) => Ok(DynVal::from(true)), lazy_evaluation_elvis(r#""test"?: "null".test"#) => Ok(DynVal::from("test")), jq_basic_index(r#"jq("[7,8,9]", ".[0]")"#) => Ok(DynVal::from(7)), + jq_raw_arg(r#"jq("[ \"foo\" ]", ".[0]", "r")"#) => Ok(DynVal::from("foo")), + jq_empty_arg(r#"jq("[ \"foo\" ]", ".[0]", "")"#) => Ok(DynVal::from(r#""foo""#)), + jq_invalid_arg(r#"jq("[ \"foo\" ]", ".[0]", "hello")"#) => Ok(DynVal::from(r#""foo""#)), + jq_no_arg(r#"jq("[ \"foo\" ]", ".[0]")"#) => Ok(DynVal::from(r#""foo""#)), } } diff --git a/docs/src/expression_language.md b/docs/src/expression_language.md index 150cf0ed..726ff793 100644 --- a/docs/src/expression_language.md +++ b/docs/src/expression_language.md @@ -47,14 +47,17 @@ Supported currently are the following features: - `degtorad(number)`: Converts a number from degrees to radians - `radtodeg(number)`: Converts a number from radians to degrees - `replace(string, regex, replacement)`: Replace matches of a given regex in a string - - `search(string, regex)`: Search for a given regex in a string (returns array) - - `matches(string, regex)`: check if a given string matches a given regex (returns bool) - - `captures(string, regex)`: Get the captures of a given regex in a string (returns array) - - `strlength(value)`: Gets the length of the string + - `search(string, regex)`: Search for a given regex in a string (returns array) + - `matches(string, regex)`: check if a given string matches a given regex (returns bool) + - `captures(string, regex)`: Get the captures of a given regex in a string (returns array) + - `strlength(value)`: Gets the length of the string - `substring(string, start, length)`: Return a substring of given length starting at the given index - - `arraylength(value)`: Gets the length of the array - - `objectlength(value)`: Gets the amount of entries in the object - - `jq(value, jq_filter_string)`: run a [jq](https://stedolan.github.io/jq/manual/) style command on a json value. (Uses [jaq](https://crates.io/crates/jaq) internally). + - `arraylength(value)`: Gets the length of the array + - `objectlength(value)`: Gets the amount of entries in the object + - `jq(value, jq_filter_string)`: run a [jq](https://jqlang.github.io/jq/manual/) style command on a json value. (Uses [jaq](https://crates.io/crates/jaq) internally). + - `jq(value, jq_filter_string, args)`: Emulate command line flags for jq, see [the docs](https://jqlang.github.io/jq/manual/#invoking-jq) on invoking jq for details. Invalid flags are silently ignored. + Currently supported flags: + - `"r"`: If the result is a string, it won't be formatted as a JSON string. The equivalent jq flag is `--raw-output`. - `get_env(string)`: Gets the specified enviroment variable - `formattime(unix_timestamp, format_str, timezone)`: Gets the time in a given format from UNIX timestamp. Check [chrono's documentation](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) for more