diff --git a/Cargo.lock b/Cargo.lock index 5fd6a7a..5f15978 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,9 +28,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -43,15 +43,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -161,9 +161,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.56" +version = "1.2.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" dependencies = [ "find-msvc-tools", "shlex", @@ -188,9 +188,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.60" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", "clap_derive", @@ -198,9 +198,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.60" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -210,9 +210,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.55" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" dependencies = [ "heck", "proc-macro2", @@ -222,9 +222,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "clipboard-win" @@ -237,9 +237,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "convert_case" @@ -447,9 +447,9 @@ dependencies = [ [[package]] name = "dispatch2" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ "bitflags", "objc2", @@ -766,9 +766,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "image" -version = "0.25.9" +version = "0.25.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" dependencies = [ "bytemuck", "byteorder-lite", @@ -867,9 +867,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.90" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dc6f6450b3f6d4ed5b16327f38fed626d375a886159ca555bd7822c0c3a5a6" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -877,9 +877,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.182" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libm" @@ -889,11 +889,10 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" dependencies = [ - "bitflags", "libc", ] @@ -954,9 +953,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.7.11" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" dependencies = [ "num-traits", "pxfm", @@ -982,9 +981,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ "objc2-encode", ] @@ -1055,9 +1054,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" @@ -1123,9 +1122,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkg-config" @@ -1157,9 +1156,9 @@ dependencies = [ [[package]] name = "promkit-core" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed89f85398b2590095afe8fb4852c177d09f568836c206a9bed823bf1e70a051" +checksum = "26da2c38cb21f2c5470a00868b513916d904f3fd6aef947962a5a06350651c49" dependencies = [ "anyhow", "crossbeam-skiplist", @@ -1170,9 +1169,9 @@ dependencies = [ [[package]] name = "promkit-widgets" -version = "0.3.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fe0c1c9d4a39811769fc7787df265e5705d2749fd6d768e1166b6dbced2927c" +checksum = "2863f757bfc30b08ba1e0f54c7e1fe3ea62b46ad44fa82cff0849f1293f29188" dependencies = [ "anyhow", "promkit-core", @@ -1180,16 +1179,14 @@ dependencies = [ "serde", "serde_json", "termcfg", + "tokio", ] [[package]] name = "pxfm" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" -dependencies = [ - "num-traits", -] +checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" [[package]] name = "quick-error" @@ -1199,18 +1196,18 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.38.4" +version = "0.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.44" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -1347,9 +1344,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" dependencies = [ "serde_core", ] @@ -1411,12 +1408,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1489,9 +1486,9 @@ dependencies = [ [[package]] name = "tiff" -version = "0.10.3" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" dependencies = [ "fax", "flate2", @@ -1503,9 +1500,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.49.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ "bytes", "libc", @@ -1520,9 +1517,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", @@ -1552,7 +1549,7 @@ dependencies = [ "toml_datetime", "toml_parser", "toml_writer", - "winnow", + "winnow 0.7.15", ] [[package]] @@ -1566,18 +1563,18 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.9+spec-1.1.0" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" dependencies = [ - "winnow", + "winnow 1.0.0", ] [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" [[package]] name = "tree_magic_mini" @@ -1634,9 +1631,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasm-bindgen" -version = "0.2.113" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60722a937f594b7fde9adb894d7c092fc1bb6612897c46368d18e7a20208eff2" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -1647,9 +1644,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.113" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac8c6395094b6b91c4af293f4c79371c163f9a6f56184d2c9a85f5a95f3950" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1657,9 +1654,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.113" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3fabce6159dc20728033842636887e4877688ae94382766e00b180abac9d60" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", @@ -1670,18 +1667,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.113" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0e091bdb824da87dc01d967388880d017a0a9bc4f3bdc0d86ee9f9336e3bb5" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] [[package]] name = "wayland-backend" -version = "0.3.12" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee64194ccd96bf648f42a65a7e589547096dfa702f7cadef84347b66ad164f9" +checksum = "aa75f400b7f719bcd68b3f47cd939ba654cedeef690f486db71331eec4c6a406" dependencies = [ "cc", "downcast-rs", @@ -1692,9 +1689,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.12" +version = "0.31.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec" +checksum = "ab51d9f7c071abeee76007e2b742499e535148035bb835f97aaed1338cf516c3" dependencies = [ "bitflags", "rustix", @@ -1704,9 +1701,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.10" +version = "0.32.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baeda9ffbcfc8cd6ddaade385eaf2393bd2115a69523c735f12242353c3df4f3" +checksum = "b23b5df31ceff1328f06ac607591d5ba360cf58f90c8fad4ac8d3a55a3c4aec7" dependencies = [ "bitflags", "wayland-backend", @@ -1716,9 +1713,9 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9597cdf02cf0c34cd5823786dce6b5ae8598f05c2daf5621b6e178d4f7345f3" +checksum = "78248e4cc0eff8163370ba5c158630dcae1f3497a586b826eca2ef5f348d6235" dependencies = [ "bitflags", "wayland-backend", @@ -1729,9 +1726,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.8" +version = "0.31.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5423e94b6a63e68e439803a3e153a9252d5ead12fd853334e2ad33997e3889e3" +checksum = "c86287151a309799b821ca709b7345a048a2956af05957c89cb824ab919fa4e3" dependencies = [ "proc-macro2", "quick-xml", @@ -1740,9 +1737,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.8" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6dbfc3ac5ef974c92a2235805cc0114033018ae1290a72e474aa8b28cbbdfd" +checksum = "374f6b70e8e0d6bf9461a32988fd553b59ff630964924dad6e4a4eb6bd538d17" dependencies = [ "pkg-config", ] @@ -1919,9 +1916,15 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.14" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" + +[[package]] +name = "winnow" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" [[package]] name = "wl-clipboard-rs" @@ -1960,18 +1963,18 @@ checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" [[package]] name = "zerocopy" -version = "0.8.39" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.39" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" dependencies = [ "proc-macro2", "quote", @@ -1986,15 +1989,15 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "zune-core" -version = "0.4.12" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" [[package]] name = "zune-jpeg" -version = "0.4.21" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c" dependencies = [ "zune-core", ] diff --git a/Cargo.toml b/Cargo.toml index 8cd144f..ddd2b54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" anyhow = "1.0.102" arboard = { version = "3.6.1", features = ["wayland-data-control"] } async-trait = "0.1.89" -clap = { version = "4.5.60", features = ["derive"] } +clap = { version = "4.6.0", features = ["derive"] } duration-string = { version = "0.5.3", features = ["serde"] } derive_builder = "0.20.2" dirs = "6.0.0" @@ -20,7 +20,7 @@ futures = "0.3.32" rustix = { version = "1.1.4", features = ["stdio"] } serde = "1.0.228" termcfg = { version = "0.2.0", features = ["crossterm_0_29_0"] } -tokio = { version = "1.49.0", features = ["full"] } +tokio = { version = "1.50.0", features = ["full"] } tokio-stream = "0.1.18" toml = "0.9.8" @@ -30,8 +30,8 @@ jaq-json = { version = "1.1.3", features = ["serde_json"] } jaq-std = "2.1.2" [dependencies.promkit-widgets] -version = "0.3.1" -features = ["jsonstream", "listbox", "serde", "text", "texteditor"] +version = "0.5.0" +features = ["jsonstream", "listbox", "serde", "spinner", "status", "texteditor"] default-features = false # The profile that 'cargo dist' will build with diff --git a/src/editor.rs b/src/editor.rs index 792f3a7..7a39e60 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -2,13 +2,11 @@ use std::{future::Future, pin::Pin}; use promkit_widgets::{ core::{ - crossterm::{ - event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}, - style::{Color, ContentStyle}, - }, - Pane, PaneFactory, + crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}, + grapheme::StyledGraphemes, + Widget, }, - text::{self, Text}, + status::{self, Severity}, text_editor, }; @@ -19,7 +17,7 @@ pub struct Editor { state: text_editor::State, focus_config: text_editor::Config, defocus_config: text_editor::Config, - guide: text::State, + guide: status::State, searcher: IncrementalSearcher, editor_keybinds: EditorKeybinds, } @@ -37,7 +35,7 @@ impl Editor { state, focus_config, defocus_config, - guide: text::State::default(), + guide: status::State::default(), searcher, editor_keybinds, } @@ -53,23 +51,23 @@ impl Editor { self.searcher.leave_search(); self.handler = BOXED_EDITOR_HANDLER; - self.guide.text = Default::default(); + self.guide = status::State::default(); } pub fn text(&self) -> String { self.state.texteditor.text_without_cursor().to_string() } - pub fn create_editor_pane(&self, width: u16, height: u16) -> Pane { - self.state.create_pane(width, height) + pub fn create_editor_pane(&self, width: u16, height: u16) -> StyledGraphemes { + self.state.create_graphemes(width, height) } - pub fn create_searcher_pane(&self, width: u16, height: u16) -> Pane { + pub fn create_searcher_pane(&self, width: u16, height: u16) -> StyledGraphemes { self.searcher.create_pane(width, height) } - pub fn create_guide_pane(&self, width: u16, height: u16) -> Pane { - self.guide.create_pane(width, height) + pub fn create_guide_pane(&self, width: u16, height: u16) -> StyledGraphemes { + self.guide.create_graphemes(width, height) } pub async fn operate(&mut self, event: &Event) -> anyhow::Result<()> { @@ -92,7 +90,7 @@ const BOXED_SEARCHER_HANDLER: Handler = }; pub async fn edit<'a>(event: &'a Event, editor: &'a mut Editor) -> anyhow::Result<()> { - editor.guide.text = Default::default(); + editor.guide = status::State::default(); match event { key if editor.editor_keybinds.completion.contains(key) => { @@ -101,42 +99,37 @@ pub async fn edit<'a>(event: &'a Event, editor: &'a mut Editor) -> anyhow::Resul Ok(result) => match result.head_item { Some(head) => { if result.load_state.loaded { - editor.guide.text = Text::from(format!( - "Loaded all ({}) suggestions", - result.load_state.loaded_item_len - )); - editor.guide.config.style = Some(ContentStyle { - foreground_color: Some(Color::Green), - ..Default::default() - }); + editor.guide = status::State::new( + format!( + "Loaded all ({}) suggestions", + result.load_state.loaded_item_len + ), + Severity::Success, + ); } else { - editor.guide.text = Text::from(format!( - "Loaded partially ({}) suggestions", - result.load_state.loaded_item_len - )); - editor.guide.config.style = Some(ContentStyle { - foreground_color: Some(Color::Green), - ..Default::default() - }); + editor.guide = status::State::new( + format!( + "Loaded partially ({}) suggestions", + result.load_state.loaded_item_len + ), + Severity::Success, + ); } editor.state.texteditor.replace(&head); editor.handler = BOXED_SEARCHER_HANDLER; } None => { - editor.guide.text = - Text::from(format!("No suggestion found for '{prefix}'")); - editor.guide.config.style = Some(ContentStyle { - foreground_color: Some(Color::Yellow), - ..Default::default() - }); + editor.guide = status::State::new( + format!("No suggestion found for '{prefix}'"), + Severity::Warning, + ); } }, Err(e) => { - editor.guide.text = Text::from(format!("Failed to lookup suggestions: {e}")); - editor.guide.config.style = Some(ContentStyle { - foreground_color: Some(Color::Yellow), - ..Default::default() - }); + editor.guide = status::State::new( + format!("Failed to lookup suggestions: {e}"), + Severity::Warning, + ); } } } diff --git a/src/json.rs b/src/json.rs index 1bd93c2..348b0d7 100644 --- a/src/json.rs +++ b/src/json.rs @@ -5,17 +5,10 @@ use jaq_core::{ use jaq_json::Val; use promkit_widgets::{ - core::{ - crossterm::{ - event::Event, - style::{Attribute, Attributes, Color, ContentStyle}, - }, - pane::Pane, - PaneFactory, - }, + core::{crossterm::event::Event, grapheme::StyledGraphemes, Widget}, jsonstream::{self, config::Config as JsonStreamConfig, jsonz, JsonStream}, serde_json::{self, Deserializer, Value}, - text::{self, Text}, + status::{self, Severity}, }; use crate::{ @@ -93,63 +86,50 @@ impl Visualizer for Json { self.state.config.format_raw_json(self.state.stream.rows()) } - async fn create_init_pane(&mut self, area: (u16, u16)) -> Pane { - self.state.create_pane(area.0, area.1) + async fn create_init_pane(&mut self, area: (u16, u16)) -> StyledGraphemes { + self.state.create_graphemes(area.0, area.1) } - async fn create_pane_from_event(&mut self, area: (u16, u16), event: &Event) -> Pane { + async fn create_pane_from_event(&mut self, area: (u16, u16), event: &Event) -> StyledGraphemes { self.operate(event); - self.state.create_pane(area.0, area.1) + self.state.create_graphemes(area.0, area.1) } async fn create_panes_from_query( &mut self, area: (u16, u16), input: String, - ) -> (Option, Option) { + ) -> (Option, Option) { match run_jaq(&input, self.json) { Ok(ret) => { let mut guide = None; if ret.iter().all(|val| *val == Value::Null) { - guide = Some(text::State { - text: Text::from(format!("jq returned 'null', which may indicate a typo or incorrect filter: `{input}`")), - config: text::Config { - style: Some(ContentStyle { - foreground_color: Some(Color::Yellow), - attributes: Attributes::from(Attribute::Bold), - ..Default::default() - }), - ..Default::default() - }, - ..Default::default() - }.create_pane(area.0, area.1)); + guide = Some( + status::State::new( + format!( + "jq returned 'null', which may indicate a typo or incorrect filter: `{input}`" + ), + Severity::Warning, + ) + .create_graphemes(area.0, area.1), + ); self.state.stream = JsonStream::new(self.json.iter()); } else { self.state.stream = JsonStream::new(ret.iter()); } - (guide, Some(self.state.create_pane(area.0, area.1))) + (guide, Some(self.state.create_graphemes(area.0, area.1))) } Err(e) => { self.state.stream = JsonStream::new(self.json.iter()); ( Some( - text::State { - text: Text::from(format!("jq failed: `{e}`")), - config: text::Config { - style: Some(ContentStyle { - foreground_color: Some(Color::Red), - attributes: Attributes::from(Attribute::Bold), - ..Default::default() - }), - ..Default::default() - }, - } - .create_pane(area.0, area.1), + status::State::new(format!("jq failed: `{e}`"), Severity::Error) + .create_graphemes(area.0, area.1), ), - Some(self.state.create_pane(area.0, area.1)), + Some(self.state.create_graphemes(area.0, area.1)), ) } } diff --git a/src/main.rs b/src/main.rs index 393d505..38e2ee7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,8 +21,7 @@ mod stdout_redirect; use stdout_redirect::StdoutRedirect; mod processor; use processor::{ - init::ViewInitializer, monitor::ContextMonitor, spinner::SpinnerSpawner, Context, Processor, - ViewProvider, Visualizer, + init::ViewInitializer, monitor::ContextMonitor, Context, Processor, ViewProvider, Visualizer, }; mod prompt; mod search; diff --git a/src/processor.rs b/src/processor.rs index e70db38..3e588e0 100644 --- a/src/processor.rs +++ b/src/processor.rs @@ -2,9 +2,7 @@ use std::sync::Arc; use async_trait::async_trait; use promkit_widgets::core::{ - crossterm::event::Event, - pane::{Pane, EMPTY_PANE}, - render::SharedRenderer, + crossterm::event::Event, grapheme::StyledGraphemes, render::SharedRenderer, }; use tokio::{sync::Mutex, task::JoinHandle}; @@ -13,7 +11,10 @@ pub use init::ViewProvider; use crate::prompt::Index; pub mod monitor; -pub mod spinner; + +fn empty_pane() -> StyledGraphemes { + StyledGraphemes::default() +} #[derive(PartialEq)] enum State { @@ -25,13 +26,13 @@ enum State { #[async_trait] pub trait Visualizer: Send + Sync + 'static { async fn content_to_copy(&self) -> String; - async fn create_init_pane(&mut self, area: (u16, u16)) -> Pane; - async fn create_pane_from_event(&mut self, area: (u16, u16), event: &Event) -> Pane; + async fn create_init_pane(&mut self, area: (u16, u16)) -> StyledGraphemes; + async fn create_pane_from_event(&mut self, area: (u16, u16), event: &Event) -> StyledGraphemes; async fn create_panes_from_query( &mut self, area: (u16, u16), query: String, - ) -> (Option, Option); + ) -> (Option, Option); } pub struct Context { @@ -90,11 +91,8 @@ impl Processor { // TODO: error handling let _ = shared_renderer .update([ - (Index::Guide, maybe_guide.unwrap_or(EMPTY_PANE.to_owned())), - ( - Index::Processor, - maybe_resp.unwrap_or(EMPTY_PANE.to_owned()), - ), + (Index::Guide, maybe_guide.unwrap_or_else(empty_pane)), + (Index::Processor, maybe_resp.unwrap_or_else(empty_pane)), ]) .render() .await; diff --git a/src/processor/monitor.rs b/src/processor/monitor.rs index b72a68a..7775d5f 100644 --- a/src/processor/monitor.rs +++ b/src/processor/monitor.rs @@ -1,5 +1,6 @@ -use std::sync::Arc; +use std::{future::Future, sync::Arc}; +use promkit_widgets::spinner; use tokio::sync::Mutex; use super::{Context, State}; @@ -12,9 +13,14 @@ impl ContextMonitor { pub fn new(shared: Arc>) -> Self { Self { shared } } +} - pub async fn is_idle(&self) -> bool { - let context = self.shared.lock().await; - context.state == State::Idle +impl spinner::State for ContextMonitor { + fn is_idle(&self) -> impl Future + Send { + let shared = self.shared.clone(); + async move { + let context = shared.lock().await; + context.state == State::Idle + } } } diff --git a/src/processor/spinner.rs b/src/processor/spinner.rs deleted file mode 100644 index b0e36d5..0000000 --- a/src/processor/spinner.rs +++ /dev/null @@ -1,53 +0,0 @@ -use std::sync::Arc; - -use promkit_widgets::core::{grapheme::StyledGraphemes, render::SharedRenderer, Pane}; -use tokio::{sync::Mutex, task::JoinHandle, time::Duration}; - -use crate::prompt::Index; - -use super::{Context, State}; - -const LOADING_FRAMES: [&str; 10] = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; - -pub struct SpinnerSpawner { - shared: Arc>, -} - -impl SpinnerSpawner { - pub fn new(shared: Arc>) -> Self { - Self { shared } - } - - pub fn spawn_spin_task( - &self, - shared_renderer: SharedRenderer, - spin_duration: Duration, - ) -> JoinHandle<()> { - let shared = self.shared.clone(); - let mut frame_index = 0; - tokio::spawn(async move { - let mut interval = tokio::time::interval(spin_duration); - loop { - interval.tick().await; - - { - let shared_state = shared.lock().await; - if shared_state.state == State::Idle { - continue; - } - } - - frame_index = (frame_index + 1) % LOADING_FRAMES.len(); - - let pane = Pane::new(vec![StyledGraphemes::from(LOADING_FRAMES[frame_index])], 0); - { - // TODO: error handling - let _ = shared_renderer - .update([(Index::Processor, pane)]) - .render() - .await; - } - } - }) - } -} diff --git a/src/prompt.rs b/src/prompt.rs index 2f55685..52afd75 100644 --- a/src/prompt.rs +++ b/src/prompt.rs @@ -11,14 +11,14 @@ use promkit_widgets::{ MouseEventKind, }, execute, - style::{Color, ContentStyle}, terminal::{self, disable_raw_mode, enable_raw_mode}, }, - pane::EMPTY_PANE, + grapheme::StyledGraphemes, render::{Renderer, SharedRenderer}, - PaneFactory, + Widget, }, - text::{self, Text}, + spinner::{self, Spinner, State}, + status::{self, Severity}, }; use tokio::{ sync::{mpsc, Mutex, RwLock}, @@ -27,8 +27,8 @@ use tokio::{ use crate::{ config::{Keybinds, ReactivityControl}, - Context, ContextMonitor, Editor, Processor, SearchProvider, SpinnerSpawner, ViewInitializer, - ViewProvider, Visualizer, + Context, ContextMonitor, Editor, Processor, SearchProvider, ViewInitializer, ViewProvider, + Visualizer, }; fn spawn_debouncer( @@ -58,55 +58,31 @@ fn spawn_debouncer( }) } -fn copy_to_clipboard(content: &str) -> text::State { +fn copy_to_clipboard(content: &str) -> status::State { match Clipboard::new() { Ok(mut clipboard) => match clipboard.set_text(content) { - Ok(_) => text::State { - text: Text::from("Copied to clipboard"), - config: text::Config { - style: Some(ContentStyle { - foreground_color: Some(Color::Green), - ..Default::default() - }), - ..Default::default() - }, - ..Default::default() - }, - Err(e) => text::State { - text: Text::from(format!("Failed to copy to clipboard: {e}")), - config: text::Config { - style: Some(ContentStyle { - foreground_color: Some(Color::Red), - ..Default::default() - }), - ..Default::default() - }, - ..Default::default() - }, + Ok(_) => status::State::new("Copied to clipboard", Severity::Success), + Err(e) => { + status::State::new(format!("Failed to copy to clipboard: {e}"), Severity::Error) + } }, // arboard fails (in the specific environment like linux?) on Clipboard::new() // suppress the errors (but still show them) not to break the prompt // https://github.com/1Password/arboard/issues/153 - Err(e) => text::State { - text: Text::from(format!("Failed to setup clipboard: {e}")), - config: text::Config { - style: Some(ContentStyle { - foreground_color: Some(Color::Red), - ..Default::default() - }), - ..Default::default() - }, - ..Default::default() - }, + Err(e) => status::State::new(format!("Failed to setup clipboard: {e}"), Severity::Error), } } +fn empty_pane() -> StyledGraphemes { + StyledGraphemes::default() +} + enum Focus { Editor, Processor, } -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum Index { Editor = 0, Guide = 1, @@ -131,12 +107,12 @@ pub async fn run( let size = terminal::size()?; let shared_renderer = SharedRenderer::new( - Renderer::try_new_with_panes( + Renderer::try_new_with_graphemes( [ (Index::Editor, editor.create_editor_pane(size.0, size.1)), - (Index::Guide, EMPTY_PANE.to_owned()), - (Index::Search, EMPTY_PANE.to_owned()), - (Index::Processor, EMPTY_PANE.to_owned()), + (Index::Guide, empty_pane()), + (Index::Search, empty_pane()), + (Index::Processor, empty_pane()), ] .into_iter(), true, @@ -165,9 +141,15 @@ pub async fn run( reactivity_control.resize_debounce_duration, ); - let spinner_spawner = SpinnerSpawner::new(ctx.clone()); - let spinning = - spinner_spawner.spawn_spin_task(shared_renderer.clone(), reactivity_control.spin_duration); + let spinning = tokio::spawn({ + let shared_renderer = shared_renderer.clone(); + let state = ContextMonitor::new(ctx.clone()); + let spin_duration = reactivity_control.spin_duration; + async move { + let spinner = Spinner::default().duration(spin_duration); + let _ = spinner::run(&spinner, state, Index::Processor, shared_renderer).await; + } + }); let mut focus = Focus::Editor; let (editor_event_tx, mut editor_event_rx) = mpsc::channel::(1); @@ -235,17 +217,11 @@ pub async fn run( shared_renderer.update([ ( Index::Guide, - text::State { - text: Text::from("Failed to copy while rendering is in progress.".to_string()), - config: text::Config { - style: Some(ContentStyle { - foreground_color: Some(Color::Yellow), - ..Default::default() - }), - ..Default::default() - }, - ..Default::default() - }.create_pane(size.0, size.1), + status::State::new( + "Failed to copy while rendering is in progress.", + Severity::Warning, + ) + .create_graphemes(size.0, size.1), ), ]).render().await?; } @@ -266,17 +242,12 @@ pub async fn run( shared_renderer.update([ ( Index::Guide, - text::State { - text: Text::from("Failed to switch pane while rendering is in progress.".to_string()), - config: text::Config { - style: Some(ContentStyle { - foreground_color: Some(Color::Yellow), - ..Default::default() - }), - ..Default::default() - }, - ..Default::default() - }.create_pane(size.0, size.1)), + status::State::new( + "Failed to switch pane while rendering is in progress.", + Severity::Warning, + ) + .create_graphemes(size.0, size.1), + ), ]).render().await?; } }, @@ -333,7 +304,7 @@ pub async fn run( }; shared_renderer.update([ (Index::Editor, editor_pane), - (Index::Guide, if !no_hint { guide_pane } else { EMPTY_PANE.to_owned() }), + (Index::Guide, if !no_hint { guide_pane } else { empty_pane() }), ]).render().await?; } Some(()) = editor_copy_rx.recv() => { @@ -344,7 +315,7 @@ pub async fn run( let guide = copy_to_clipboard(&text); if !no_hint { let size = terminal::size()?; - let pane = guide.create_pane(size.0, size.1); + let pane = guide.create_graphemes(size.0, size.1); shared_renderer.update([ (Index::Guide, pane), ]).render().await?; @@ -372,7 +343,7 @@ pub async fn run( { shared_renderer.update([ (Index::Editor, editor_pane), - (Index::Guide, if !no_hint { guide_pane } else { EMPTY_PANE.to_owned() }), + (Index::Guide, if !no_hint { guide_pane } else { empty_pane() }), (Index::Search, searcher_pane), ]).render().await?; } @@ -399,7 +370,7 @@ pub async fn run( let guide = copy_to_clipboard(&visualizer.content_to_copy().await); if !no_hint { let size = terminal::size()?; - let pane = guide.create_pane(size.0, size.1); + let pane = guide.create_graphemes(size.0, size.1); shared_renderer.update([ (Index::Guide, pane), ]).render().await?; @@ -435,7 +406,7 @@ pub async fn run( { shared_renderer.update([ (Index::Editor, editor_pane), - (Index::Guide, if !no_hint { guide_pane } else { EMPTY_PANE.to_owned() }), + (Index::Guide, if !no_hint { guide_pane } else { empty_pane() }), (Index::Search, searcher_pane), ]).render().await?; } diff --git a/src/search.rs b/src/search.rs index 93ce6a9..b46869f 100644 --- a/src/search.rs +++ b/src/search.rs @@ -3,7 +3,7 @@ use std::{collections::BTreeSet, sync::Arc}; use anyhow::anyhow; use async_trait::async_trait; use promkit_widgets::{ - core::{pane::Pane, PaneFactory}, + core::{grapheme::StyledGraphemes, Widget}, listbox::{self, Listbox}, }; use tokio::{ @@ -111,8 +111,8 @@ impl IncrementalSearcher { self.state.listbox.get().to_string() } - pub fn create_pane(&self, width: u16, height: u16) -> Pane { - self.state.create_pane(width, height) + pub fn create_pane(&self, width: u16, height: u16) -> StyledGraphemes { + self.state.create_graphemes(width, height) } pub fn leave_search(&mut self) {