From 4a1e2f2e925f259ab97389bc3f85103e941e7243 Mon Sep 17 00:00:00 2001 From: ynqa Date: Sun, 26 May 2024 23:15:59 +0900 Subject: [PATCH 1/9] bump up version to v0.3.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f8624ef..351804a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -350,7 +350,7 @@ dependencies = [ [[package]] name = "jnv" -version = "0.2.3" +version = "0.3.0" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 3a95a03..5f864a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jnv" -version = "0.2.3" +version = "0.3.0" authors = ["ynqa "] edition = "2021" description = "JSON navigator and interactive filter leveraging jq" From a3fdca72b67b78bf831de5d7fd9ef2f40e5264b3 Mon Sep 17 00:00:00 2001 From: ynqa Date: Sun, 21 Apr 2024 22:45:55 +0900 Subject: [PATCH 2/9] use jaq --- Cargo.lock | 345 +++++++++++++++++++++++++++------------------------- Cargo.toml | 5 +- src/jnv.rs | 162 ++++++++---------------- src/main.rs | 29 ++++- 4 files changed, 265 insertions(+), 276 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 351804a..ef2b240 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,19 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -11,6 +24,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "anstream" version = "0.6.13" @@ -72,35 +91,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] -name = "autotools" -version = "0.2.7" +name = "base64" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef941527c41b0fc0dd48511a8154cd5fc7e29200a0ff8b7203c5d777dbc795cf" -dependencies = [ - "cc", -] +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] -name = "bindgen" -version = "0.69.4" +name = "bincode" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "bitflags 2.5.0", - "cexpr", - "clang-sys", - "itertools", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", - "which", + "serde", ] [[package]] @@ -115,21 +117,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" -[[package]] -name = "cc" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -137,14 +124,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "clang-sys" -version = "1.7.0" +name = "chumsky" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9" dependencies = [ - "glob", - "libc", - "libloading", + "hashbrown", ] [[package]] @@ -220,10 +205,19 @@ dependencies = [ ] [[package]] -name = "either" -version = "1.11.0" +name = "deranged" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "endian-type" @@ -275,16 +269,25 @@ dependencies = [ ] [[package]] -name = "glob" -version = "0.3.1" +name = "getrandom" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] [[package]] name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] [[package]] name = "heck" @@ -293,13 +296,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "home" -version = "0.5.9" +name = "hifijson" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] +checksum = "18ae468bcb4dfecf0e4949ee28abbc99076b6a0077f51ddbc94dbfff8e6a870c" [[package]] name = "indexmap" @@ -312,40 +312,71 @@ dependencies = [ ] [[package]] -name = "itertools" -version = "0.12.1" +name = "itoa" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jaq-core" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d6a5713b8f33675abfac79d1db0022a3f28764b2a6b96a185c199ad8dab86d" dependencies = [ - "either", + "aho-corasick", + "base64", + "hifijson", + "jaq-interpret", + "libm", + "log", + "regex", + "time", + "urlencoding", ] [[package]] -name = "itoa" -version = "1.0.11" +name = "jaq-interpret" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "f569e38e5fc677db8dfda89ee0b4c25b3f53e811b16434fd14bdc5b43fc362ac" +dependencies = [ + "ahash", + "dyn-clone", + "hifijson", + "indexmap", + "jaq-syn", + "once_cell", + "serde_json", +] [[package]] -name = "j9" -version = "0.1.3" +name = "jaq-parse" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2876f6d536ef88276de82d5c4c76a463b9f7ebaee288b49284aeacfca7b699" +checksum = "ef6f8beb9f9922546419e774e24199e8a968f54c63a5a2323c8f3ef3321ace14" dependencies = [ - "j9-sys", - "thiserror", + "chumsky", + "jaq-syn", ] [[package]] -name = "j9-sys" -version = "0.1.3" +name = "jaq-std" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe8caa9c5f8d1b56e4191614bed237d2f9081d933ac3884cafab1100f37d0afd" +checksum = "5d7871c59297cbfdd18f6f1bbbafaad24e97fd555ee1e2a1be7a40a5a20f551a" dependencies = [ - "anyhow", - "autotools", - "bindgen", - "walkdir", + "bincode", + "jaq-parse", + "jaq-syn", +] + +[[package]] +name = "jaq-syn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4d60101fb791b20c982731d848ed6e7d25363656497647c2093b68bd88398d6" +dependencies = [ + "serde", ] [[package]] @@ -355,23 +386,14 @@ dependencies = [ "anyhow", "clap", "gag", - "j9", + "jaq-core", + "jaq-interpret", + "jaq-parse", + "jaq-std", "promkit", "radix_trie", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.153" @@ -379,14 +401,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] -name = "libloading" -version = "0.8.3" +name = "libm" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" -dependencies = [ - "cfg-if", - "windows-targets 0.52.5", -] +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "linux-raw-sys" @@ -416,12 +434,6 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "mio" version = "0.8.11" @@ -444,14 +456,10 @@ dependencies = [ ] [[package]] -name = "nom" -version = "7.1.3" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "once_cell" @@ -483,14 +491,10 @@ dependencies = [ ] [[package]] -name = "prettyplease" -version = "0.2.19" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac2cf0f2e4f42b49f5ffd07dae8d746508ef7526c13940e5f524012ae6c6550" -dependencies = [ - "proc-macro2", - "syn", -] +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "proc-macro2" @@ -573,12 +577,6 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustix" version = "0.38.32" @@ -598,15 +596,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -645,12 +634,6 @@ dependencies = [ "serde", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "signal-hook" version = "0.3.17" @@ -736,6 +719,37 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -748,6 +762,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf8parse" version = "0.2.1" @@ -755,14 +775,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] -name = "walkdir" -version = "2.5.0" +name = "version_check" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" @@ -770,18 +786,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "winapi" version = "0.3.9" @@ -798,15 +802,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -951,3 +946,23 @@ name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 5f864a3..89822f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,10 @@ readme = "README.md" anyhow = "1.0.82" clap = { version = "4.5.4", features = ["derive"] } gag = "1.0.0" -j9 = "0.1.3" +jaq-core = "1.2.1" +jaq-interpret = "1.2.1" +jaq-parse = "1.0.2" +jaq-std = "1.2.1" promkit = "0.4.3" radix_trie = "0.2.1" diff --git a/src/jnv.rs b/src/jnv.rs index 4bd5c88..792b921 100644 --- a/src/jnv.rs +++ b/src/jnv.rs @@ -1,7 +1,8 @@ use std::cell::RefCell; use anyhow::Result; -use gag::Gag; + +use jaq_interpret::{Ctx, FilterT, ParseCtx, RcIter, Val}; use promkit::{ crossterm::{ @@ -11,7 +12,7 @@ use promkit::{ json::{self, JsonNode, JsonPathSegment, JsonStream}, listbox, pane::Pane, - serde_json::{self, Deserializer}, + serde_json, snapshot::Snapshot, style::StyleBuilder, suggest::Suggest, @@ -23,64 +24,37 @@ use crate::trie::FilterTrie; mod keymap; -/// Deserializes a JSON string into a vector of `serde_json::Value`. -/// -/// This function takes a JSON string as input and attempts to parse it into a vector -/// of `serde_json::Value`, which represents any valid JSON value (e.g., object, array, string, number). -/// It leverages `serde_json::Deserializer` to parse the string and collect the results. -/// -/// # Arguments -/// * `json_str` - A string slice that holds the JSON data to be deserialized. -/// -/// # Returns -/// An `anyhow::Result` wrapping a vector of `serde_json::Value`. On success, it contains the parsed -/// JSON data. On failure, it contains an error detailing what went wrong during parsing. -fn deserialize_json( - json_str: &str, - limit_length: Option, +fn run_jaq( + query: &str, + json_stream: Vec, ) -> anyhow::Result> { - let deserializer = Deserializer::from_str(json_str).into_iter::(); - let results = match limit_length { - Some(l) => deserializer.take(l).collect::, _>>(), - None => deserializer.collect::, _>>(), - }; - results.map_err(anyhow::Error::from) -} + let mut ret = Vec::::new(); -fn run_jq(query: &str, json_stream: &[serde_json::Value]) -> anyhow::Result> { - // libjq writes to the console when an internal error occurs. - // - // e.g. - // ``` - // let _ = j9::run(". | select(.number == invalid_no_quote)", "{}"); - // jq: error: invalid_no_quote/0 is not defined at , line 1: - // . | select(.number == invalid_no_quote) - // ``` - // - // While errors themselves are not an issue, - // they interfere with the console output handling mechanism - // in promkit and qjq (e.g., causing line numbers to shift). - // Therefore, we'll ignore console output produced inside j9::run. - // - // It's possible that this could be handled - // within github.com/ynqa/j9, but for now, - // we'll proceed with this workaround. - // - // For reference, the functionality of a quiet mode in libjq is - // also being discussed at https://github.com/jqlang/jq/issues/1225. - let ignore_err = Gag::stderr().unwrap(); - let mut jq_ret = Vec::::new(); - for v in json_stream.iter() { - let inner_ret: Vec = match j9::run(query, &v.to_string()) { - Ok(ret) => ret, - Err(e) => { - return Err(anyhow::anyhow!(e)); - } - }; - jq_ret.extend(inner_ret); + for input in json_stream { + let mut ctx = ParseCtx::new(Vec::new()); + ctx.insert_natives(jaq_core::core()); + ctx.insert_defs(jaq_std::std()); + + let (f, errs) = jaq_parse::parse(query, jaq_parse::main()); + if !errs.is_empty() { + let error_message = errs + .iter() + .map(|e| e.to_string()) + .collect::>() + .join(", "); + return Err(anyhow::anyhow!(error_message)); + } + + let f = ctx.compile(f.unwrap()); + let inputs = RcIter::new(core::iter::empty()); + let mut out = f.run((Ctx::new([], &inputs), Val::from(input))); + + while let Some(Ok(val)) = out.next() { + ret.push(val.into()); + } } - drop(ignore_err); - Ok(jq_ret) + + Ok(ret) } pub struct JsonTheme { @@ -132,24 +106,20 @@ pub struct Jnv { suggest: Suggest, json_expand_depth: Option, - json_limit_length: Option, no_hint: bool, } impl Jnv { #[allow(clippy::too_many_arguments)] pub fn try_new( - input: String, + input_stream: Vec, filter_editor: text_editor::State, hint_message: text::State, suggestions: listbox::State, json_theme: JsonTheme, json_expand_depth: Option, - json_limit_length: Option, no_hint: bool, ) -> Result> { - let input_stream = deserialize_json(&input, json_limit_length)?; - let mut trie = FilterTrie::default(); trie.insert(".", input_stream.clone()); @@ -209,7 +179,6 @@ impl Jnv { trie, suggest, json_expand_depth, - json_limit_length, no_hint, input_stream, }, @@ -284,7 +253,7 @@ impl promkit::Renderer for Jnv { ); } None => { - match run_jq(&filter, &self.input_stream) { + match run_jaq(&filter, self.input_stream.clone()) { Ok(ret) => { if ret.is_empty() { self.update_hint_message( @@ -302,53 +271,30 @@ impl promkit::Renderer for Jnv { JsonStream::new(searched.clone(), self.json_expand_depth); } } else { - match deserialize_json(&ret.join("\n"), self.json_limit_length) { - Ok(jsonl) => { - let stream = - JsonStream::new(jsonl.clone(), self.json_expand_depth); + let stream = JsonStream::new(ret.clone(), self.json_expand_depth); - let is_null = stream.roots().iter().all(|node| { - node == &JsonNode::Leaf(serde_json::Value::Null) - }); - if is_null { - self.update_hint_message( - format!("JSON query resulted in 'null', which may indicate a typo or incorrect query: '{}'", &filter), - StyleBuilder::new() - .fgc(Color::Yellow) - .attrs(Attributes::from(Attribute::Bold)) - .build(), - ); - if let Some(searched) = self.trie.prefix_search(&filter) - { - self.json.stream = JsonStream::new( - searched.clone(), - self.json_expand_depth, - ); - } - } else { - // SUCCESS! - self.trie.insert(&filter, jsonl); - self.json.stream = stream; - } - } - Err(e) => { - self.update_hint_message( - format!( - "Failed to parse query result for viewing: {}", - e - ), - StyleBuilder::new() - .fgc(Color::Red) - .attrs(Attributes::from(Attribute::Bold)) - .build(), + let is_null = stream + .roots() + .iter() + .all(|node| node == &JsonNode::Leaf(serde_json::Value::Null)); + if is_null { + self.update_hint_message( + format!("JSON query resulted in 'null', which may indicate a typo or incorrect query: '{}'", &filter), + StyleBuilder::new() + .fgc(Color::Yellow) + .attrs(Attributes::from(Attribute::Bold)) + .build(), + ); + if let Some(searched) = self.trie.prefix_search(&filter) { + self.json.stream = JsonStream::new( + searched.clone(), + self.json_expand_depth, ); - if let Some(searched) = self.trie.prefix_search(&filter) { - self.json.stream = JsonStream::new( - searched.clone(), - self.json_expand_depth, - ); - } } + } else { + // SUCCESS! + self.trie.insert(&filter, ret); + self.json.stream = stream; } } } diff --git a/src/main.rs b/src/main.rs index 70064aa..d575c92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use clap::Parser; use promkit::{ crossterm::style::{Attribute, Attributes, Color}, listbox, + serde_json::{self, Deserializer}, style::StyleBuilder, text, text_editor, }; @@ -158,10 +159,35 @@ fn parse_input(args: &Args) -> Result { Ok(ret) } +/// Deserializes a JSON string into a vector of `serde_json::Value`. +/// +/// This function takes a JSON string as input and attempts to parse it into a vector +/// of `serde_json::Value`, which represents any valid JSON value (e.g., object, array, string, number). +/// It leverages `serde_json::Deserializer` to parse the string and collect the results. +/// +/// # Arguments +/// * `json_str` - A string slice that holds the JSON data to be deserialized. +/// +/// # Returns +/// An `anyhow::Result` wrapping a vector of `serde_json::Value`. On success, it contains the parsed +/// JSON data. On failure, it contains an error detailing what went wrong during parsing. +fn deserialize_json( + json_str: &str, + limit_length: Option, +) -> anyhow::Result> { + let deserializer = Deserializer::from_str(json_str).into_iter::(); + let results = match limit_length { + Some(l) => deserializer.take(l).collect::, _>>(), + None => deserializer.collect::, _>>(), + }; + results.map_err(anyhow::Error::from) +} + fn main() -> Result<()> { let args = Args::parse(); let input = parse_input(&args)?; + let input_stream = deserialize_json(&input, args.json_limit_length)?; let filter_editor = text_editor::State { texteditor: Default::default(), @@ -216,13 +242,12 @@ fn main() -> Result<()> { }; let mut prompt = Jnv::try_new( - input, + input_stream, filter_editor, hint_message, suggestions, json_theme, args.json_expand_depth, - args.json_limit_length, args.no_hint, )?; let _ = prompt.run()?; From f0fb51c53bee27e7c07c33b62d0bd06df9829c76 Mon Sep 17 00:00:00 2001 From: ynqa Date: Sun, 26 May 2024 19:03:51 +0900 Subject: [PATCH 3/9] update Cargo.toml --- Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 89822f0..8e1dde4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,11 +35,8 @@ installers = ["homebrew"] # A GitHub repo to push Homebrew formulas to tap = "ynqa/homebrew-tap" # Target platforms to build apps for (Rust target-triple syntax) -targets = ["x86_64-apple-darwin", "x86_64-unknown-linux-gnu"] +targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"] # Publish jobs to run in CI publish-jobs = ["homebrew"] # Publish jobs to run in CI pr-run-mode = "plan" - -[workspace.metadata.dist.dependencies.homebrew] -automake = '*' From 0942fd086aaaa3327f01a26675772a16388c5ac6 Mon Sep 17 00:00:00 2001 From: ynqa Date: Sun, 26 May 2024 19:04:59 +0900 Subject: [PATCH 4/9] update workflows/ci.yml --- .github/workflows/ci.yml | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 924e7c9..84ffca2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,27 +15,6 @@ jobs: ~/.cargo/git target key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - name: Install clang package - run: | - sudo apt-get update - sudo apt-get install -y \ - build-essential \ - autoconf \ - libtool \ - git \ - wget \ - software-properties-common - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo apt-add-repository "deb http://apt.llvm.org/bullseye/ llvm-toolchain-bullseye-15 main" - sudo apt-get update - sudo apt-get install -y \ - clang-15 \ - lldb-15 \ - lld-15 - - name: Set default compiler to clang - run: | - echo "CC=clang-15" >> $GITHUB_ENV - echo "CXX=clang++-15" >> $GITHUB_ENV - uses: actions-rs/toolchain@v1 with: toolchain: stable From 41f1e1f5e90ca72cb00ebb40bc4cf483492f6bae Mon Sep 17 00:00:00 2001 From: ynqa Date: Sun, 26 May 2024 19:06:58 +0900 Subject: [PATCH 5/9] update readme --- README.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/README.md b/README.md index 305a2d2..250e436 100644 --- a/README.md +++ b/README.md @@ -61,21 +61,10 @@ nix-shell -p jnv ### Cargo -#### Requirements - -- [autoconf](https://www.gnu.org/software/autoconf/) -- [automake](https://www.gnu.org/software/automake/) -- [libtool](https://www.gnu.org/software/libtool/) -- [clang](https://clang.llvm.org/) - ```bash cargo install jnv ``` -> [!NOTE] -> *jnv* does not require users to install `jq` on their system, -> because it utilizes [j9](https://github.com/ynqa/j9) Rust bindings. - ## Examples ```bash From 59f5037f0a5256f6ee6b5e65ecd3be0a0a41cb5c Mon Sep 17 00:00:00 2001 From: ynqa Date: Mon, 27 May 2024 18:36:26 +0900 Subject: [PATCH 6/9] remove gag --- Cargo.lock | 58 ------------------------------------------------------ Cargo.toml | 1 - 2 files changed, 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef2b240..6c4778c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -231,22 +231,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "fastrand" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" - [[package]] name = "filedescriptor" version = "0.8.2" @@ -258,16 +242,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "gag" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a713bee13966e9fbffdf7193af71d54a6b35a0bb34997cd6c9519ebeb5005972" -dependencies = [ - "filedescriptor", - "tempfile", -] - [[package]] name = "getrandom" version = "0.2.14" @@ -385,7 +359,6 @@ version = "0.3.0" dependencies = [ "anyhow", "clap", - "gag", "jaq-core", "jaq-interpret", "jaq-parse", @@ -406,12 +379,6 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - [[package]] name = "lock_api" version = "0.4.11" @@ -577,19 +544,6 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" -[[package]] -name = "rustix" -version = "0.38.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" -dependencies = [ - "bitflags 2.5.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - [[package]] name = "ryu" version = "1.0.17" @@ -687,18 +641,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - [[package]] name = "thiserror" version = "1.0.59" diff --git a/Cargo.toml b/Cargo.toml index 8e1dde4..c89c896 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ readme = "README.md" [dependencies] anyhow = "1.0.82" clap = { version = "4.5.4", features = ["derive"] } -gag = "1.0.0" jaq-core = "1.2.1" jaq-interpret = "1.2.1" jaq-parse = "1.0.2" From 9d7eb789aaa7ffe592ecef17a4772b7775183378 Mon Sep 17 00:00:00 2001 From: ynqa Date: Mon, 27 May 2024 23:31:45 +0900 Subject: [PATCH 7/9] update readme~ --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 250e436..e1162a1 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ and [jiq](https://github.com/fiatjaf/jiq). - Interactive JSON viewer and `jq` filter editor - Syntax highlighting for JSON + - Use [jaq]((https://github.com/01mf02/jaq)) parser for `jq` filters + - This eliminates the need for users to prepare `jq` on their own. - Capable of accommodating various format - Input: File, Stdin - Data: A JSON or multiple JSON structures From bb066419e858c11a739abaceab2ca407e0daf273 Mon Sep 17 00:00:00 2001 From: ynqa Date: Tue, 28 May 2024 08:02:02 +0900 Subject: [PATCH 8/9] update readme~ --- README.md | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index e1162a1..17e7e7f 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ and [jiq](https://github.com/fiatjaf/jiq). - Interactive JSON viewer and `jq` filter editor - Syntax highlighting for JSON - - Use [jaq]((https://github.com/01mf02/jaq)) parser for `jq` filters + - Use [jaq](https://github.com/01mf02/jaq) to apply `jq` filter - This eliminates the need for users to prepare `jq` on their own. - Capable of accommodating various format - Input: File, Stdin @@ -118,39 +118,23 @@ Examples: cat data.json | jnv Arguments: - [INPUT] - Optional path to a JSON file. If not provided or if "-" is specified, reads from standard input + [INPUT] Optional path to a JSON file. If not provided or if "-" is specified, reads from standard input Options: -e, --edit-mode - Specifies the edit mode for the interface. - Acceptable values are "insert" or "overwrite". - - "insert" inserts a new input at the cursor's position. - - "overwrite" mode replaces existing characters with new input at the cursor's position. - [default: insert] - + Edit mode for the interface ('insert' or 'overwrite'). [default: insert] -i, --indent - Affect the formatting of the displayed JSON, - making it more readable by adjusting the indentation level. - [default: 2] - + Number of spaces used for indentation in the visualized data. [default: 2] -n, --no-hint - When this option is enabled, it prevents the display of - hints that typically guide or offer suggestions to the user. - - -d, --expand-depth - Specifies the initial depth to which JSON nodes are expanded in the visualization. - Note: Increasing this depth can significantly slow down the display for large datasets. - [default: 3] - + Disables the display of hints. + -d, --expand-depth + Initial depth to which JSON nodes are expanded in the visualization. [default: 3] + -s, --limit-length + Limit length of JSON array in the visualization. [default: 50] -l, --suggestion-list-length - Controls the number of suggestions displayed in the list, - aiding users in making selections more efficiently. - [default: 3] - + Number of suggestions visible in the list. [default: 3] -h, --help - Print help (see a summary with '-h') - + Print help (see more with '--help') -V, --version Print version ``` From 9466b75fd250ab13860e8890da3568870acd5ae6 Mon Sep 17 00:00:00 2001 From: ynqa Date: Sun, 2 Jun 2024 13:46:50 +0900 Subject: [PATCH 9/9] update readme about transition --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 17e7e7f..7de78ac 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,20 @@ and [jiq](https://github.com/fiatjaf/jiq). - Syntax highlighting for JSON - Use [jaq](https://github.com/01mf02/jaq) to apply `jq` filter - This eliminates the need for users to prepare `jq` on their own. + +> [!IMPORTANT] +> Starting from v0.3.0, the transition from libjq Rust binding +> [j9](https://github.com/ynqa/j9) to jq clone +> [jaq](https://github.com/01mf02/jaq) was made. +> +> This change eliminated the need to manage C-related dependencies +> that include external tools like autoconf, thus simplifying the build process. +> However, please note that some filters are not yet supported by jaq. +> For more details, refer to GitHub issue +> [#24](https://github.com/ynqa/jnv/issues/24). +> +> Please continue to provide feedback regarding this transition. + - Capable of accommodating various format - Input: File, Stdin - Data: A JSON or multiple JSON structures