diff --git a/CHANGELOG.md b/CHANGELOG.md index 3710363e..626d43b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to eww will be listed here, starting at changes since versio - Fix wayland monitor names support (By: dragonnn) ### Features +- 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 ecb644e7..c619da03 100644 --- a/crates/simplexpr/src/eval.rs +++ b/crates/simplexpr/src/eval.rs @@ -456,7 +456,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())), }, @@ -506,16 +508,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)] @@ -576,5 +582,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 0fb51e6a..1850793d 100644 --- a/docs/src/expression_language.md +++ b/docs/src/expression_language.md @@ -44,14 +44,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