From 58d73dbeba4074474fa41909299861635a96f866 Mon Sep 17 00:00:00 2001 From: Alexandre Pasmantier <47638216+alexpasmantier@users.noreply.github.com> Date: Tue, 6 May 2025 00:07:50 +0200 Subject: [PATCH] refactor!(previews): drop builtin previewers and all related code and dependencies (#495) BREAKING CHANGE: No more builtin previews which means channels currently using `:files:` and other builtins will now need to rely on external tools (examples to come). --- .config/config.toml | 9 - Cargo.lock | 1094 +------------------ Cargo.toml | 23 +- benches/main/ui.rs | 55 +- cable/unix-channels.toml | 4 +- cable/windows-channels.toml | 8 +- television/app.rs | 43 +- television/cable.rs | 8 +- television/channels/cable.rs | 30 +- television/channels/cable/prototypes.rs | 68 +- television/channels/entry.rs | 24 +- television/channels/mod.rs | 11 +- television/channels/preview.rs | 162 ++- television/channels/remote_control.rs | 24 +- television/channels/stdin.rs | 156 --- television/cli/args.rs | 5 +- television/cli/mod.rs | 95 +- television/config/mod.rs | 13 +- television/config/previewers.rs | 40 - television/event.rs | 92 +- television/main.rs | 63 +- television/preview/ansi.rs | 34 - television/preview/ansi/LICENSE | 7 - television/preview/ansi/code.rs | 140 --- television/preview/ansi/error.rs | 24 - television/preview/ansi/parser.rs | 461 -------- television/preview/{previewers => }/meta.rs | 22 - television/preview/mod.rs | 147 +-- television/preview/previewer.rs | 137 +++ television/preview/previewers/basic.rs | 30 - television/preview/previewers/command.rs | 294 ----- television/preview/previewers/env.rs | 50 - television/preview/previewers/files.rs | 379 ------- television/preview/previewers/mod.rs | 5 - television/screen/preview.rs | 267 +---- television/screen/results.rs | 19 +- television/television.rs | 106 +- television/utils/image.rs | 185 ---- television/utils/mod.rs | 2 - television/utils/shell.rs | 17 +- television/utils/syntax.rs | 284 ----- tests/app.rs | 46 +- 42 files changed, 650 insertions(+), 4033 deletions(-) delete mode 100644 television/channels/stdin.rs delete mode 100644 television/config/previewers.rs delete mode 100644 television/preview/ansi.rs delete mode 100644 television/preview/ansi/LICENSE delete mode 100644 television/preview/ansi/code.rs delete mode 100644 television/preview/ansi/error.rs delete mode 100644 television/preview/ansi/parser.rs rename television/preview/{previewers => }/meta.rs (50%) create mode 100644 television/preview/previewer.rs delete mode 100644 television/preview/previewers/basic.rs delete mode 100644 television/preview/previewers/command.rs delete mode 100644 television/preview/previewers/env.rs delete mode 100644 television/preview/previewers/files.rs delete mode 100644 television/preview/previewers/mod.rs delete mode 100644 television/utils/image.rs delete mode 100644 television/utils/syntax.rs diff --git a/.config/config.toml b/.config/config.toml index cd7172f..686f5c5 100644 --- a/.config/config.toml +++ b/.config/config.toml @@ -61,15 +61,6 @@ orientation = "landscape" # directory in your configuration directory (see the `config.toml` location above). theme = "default" -# Previewers settings -# ---------------------------------------------------------------------------- -[previewers.file] -# The theme to use for syntax highlighting. -# Bulitin syntax highlighting uses the same syntax highlighting engine as bat. -# To get a list of your currently available themes, run `bat --list-themes` -# Note that setting the BAT_THEME environment variable will override this setting. -theme = "TwoDark" - # Keybindings # ---------------------------------------------------------------------------- # diff --git a/Cargo.lock b/Cargo.lock index 487c23e..25e1004 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,12 +26,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aligned-vec" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" - [[package]] name = "allocator-api2" version = "0.2.21" @@ -45,12 +39,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] -name = "ansi_colours" -version = "1.2.3" +name = "ansi-to-tui" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14eec43e0298190790f41679fe69ef7a829d2a2ddd78c8c00339e84710e435fe" +checksum = "67555e1f1ece39d737e28c8a017721287753af3f93225e4a445b29ccb0f5912c" dependencies = [ - "rgb", + "nom", + "ratatui", + "simdutf8", + "smallvec", + "thiserror 1.0.69", ] [[package]] @@ -109,58 +107,12 @@ version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" -[[package]] -name = "arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" - -[[package]] -name = "arg_enum_proc_macro" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "av1-grain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" -dependencies = [ - "anyhow", - "arrayvec", - "log", - "nom", - "num-rational", - "v_frame", -] - -[[package]] -name = "avif-serialize" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e" -dependencies = [ - "arrayvec", -] - [[package]] name = "backtrace" version = "0.3.74" @@ -182,43 +134,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bat" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab792c2ad113a666f08856c88cdec0a62d732559b1f3982eedf0142571e669a" -dependencies = [ - "ansi_colours", - "anyhow", - "bincode", - "bytesize", - "clircle", - "console", - "content_inspector", - "encoding_rs", - "flate2", - "globset", - "home", - "indexmap", - "itertools 0.13.0", - "nu-ansi-term 0.50.1", - "once_cell", - "path_abs", - "plist", - "regex", - "semver", - "serde", - "serde_derive", - "serde_with", - "serde_yaml", - "syntect", - "terminal-colorsaurus", - "thiserror 1.0.69", - "toml", - "unicode-width 0.1.14", - "walkdir", -] - [[package]] name = "better-panic" version = "0.3.0" @@ -229,42 +144,6 @@ dependencies = [ "console", ] -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bit_field" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.9.0" @@ -274,58 +153,18 @@ dependencies = [ "serde", ] -[[package]] -name = "bitstream-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" - -[[package]] -name = "bstr" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "built" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" - [[package]] name = "bumpalo" version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" -[[package]] -name = "bytemuck" -version = "1.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" - -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - [[package]] name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -[[package]] -name = "bytesize" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e93abca9e28e0a1b9877922aacb20576e05d4679ffa78c3d6dc22a26a216659" - [[package]] name = "cassowary" version = "0.3.0" @@ -347,27 +186,6 @@ dependencies = [ "rustversion", ] -[[package]] -name = "cc" -version = "1.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -460,22 +278,6 @@ dependencies = [ "error-code", ] -[[package]] -name = "clircle" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9334f725b46fb9bed8580b9b47a932587e044fadb344ed7fa98774b067ac1a" -dependencies = [ - "cfg-if", - "windows", -] - -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "colorchoice" version = "1.0.3" @@ -506,28 +308,9 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.0", "windows-sys 0.59.0", ] -[[package]] -name = "content_inspector" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" -dependencies = [ - "memchr", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - [[package]] name = "criterion" version = "0.5.1" @@ -597,7 +380,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.9.0", + "bitflags", "crossterm_winapi", "filedescriptor", "mio", @@ -659,15 +442,6 @@ dependencies = [ "syn", ] -[[package]] -name = "deranged" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" -dependencies = [ - "powerfmt", -] - [[package]] name = "devicons" version = "0.6.12" @@ -710,15 +484,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -741,46 +506,12 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" -[[package]] -name = "exr" -version = "1.73.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" -dependencies = [ - "bit_field", - "half", - "lebe", - "miniz_oxide", - "rayon-core", - "smallvec", - "zune-inflate", -] - -[[package]] -name = "fancy-regex" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" -dependencies = [ - "bit-set", - "regex", -] - [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - [[package]] name = "filedescriptor" version = "0.8.3" @@ -792,16 +523,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "flate2" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" @@ -875,16 +596,6 @@ dependencies = [ "pin-utils", ] -[[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.15" @@ -908,35 +619,12 @@ dependencies = [ "wasi 0.14.2+wasi-0.2.4", ] -[[package]] -name = "gif" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" -dependencies = [ - "color_quant", - "weezl", -] - [[package]] name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "globset" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - [[package]] name = "half" version = "2.6.0" @@ -970,15 +658,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "human-panic" version = "2.0.2" @@ -1001,45 +680,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "image" -version = "0.25.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" -dependencies = [ - "bytemuck", - "byteorder-lite", - "color_quant", - "exr", - "gif", - "image-webp", - "num-traits", - "png", - "qoi", - "ravif", - "rayon", - "rgb", - "tiff", - "zune-core", - "zune-jpeg", -] - -[[package]] -name = "image-webp" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" -dependencies = [ - "byteorder-lite", - "quick-error", -] - -[[package]] -name = "imgref" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" - [[package]] name = "indexmap" version = "2.9.0" @@ -1048,7 +688,6 @@ checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", - "serde", ] [[package]] @@ -1070,17 +709,6 @@ dependencies = [ "syn", ] -[[package]] -name = "interpolate_name" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "is-terminal" version = "0.4.16" @@ -1107,15 +735,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -1131,22 +750,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "jobserver" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" -dependencies = [ - "getrandom 0.3.2", - "libc", -] - -[[package]] -name = "jpeg-decoder" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" - [[package]] name = "js-sys" version = "0.3.77" @@ -1157,41 +760,48 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy-regex" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60c7310b93682b36b98fa7ea4de998d3463ccbebd94d935d6b48ba5b6ffa7126" +dependencies = [ + "lazy-regex-proc_macros", + "once_cell", + "regex-lite", +] + +[[package]] +name = "lazy-regex-proc_macros" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba01db5ef81e17eb10a5e0f2109d1b3a3e29bac3070fdbd7d156bf7dbd206a1" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn", +] + [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lebe" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" - [[package]] name = "libc" version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" -[[package]] -name = "libfuzzer-sys" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" -dependencies = [ - "arbitrary", - "cc", -] - [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.0", + "bitflags", "libc", ] @@ -1223,15 +833,6 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -[[package]] -name = "loop9" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" -dependencies = [ - "imgref", -] - [[package]] name = "lru" version = "0.12.5" @@ -1250,16 +851,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "maybe-rayon" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" -dependencies = [ - "cfg-if", - "rayon", -] - [[package]] name = "memchr" version = "2.7.4" @@ -1279,7 +870,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", - "simd-adler32", ] [[package]] @@ -1294,12 +884,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - [[package]] name = "nom" version = "7.1.3" @@ -1310,12 +894,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "noop_proc_macro" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1326,15 +904,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "nu-ansi-term" -version = "0.50.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "nucleo" version = "0.5.0" @@ -1356,53 +925,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -1427,28 +949,6 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -[[package]] -name = "onig" -version = "6.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" -dependencies = [ - "bitflags 1.3.2", - "libc", - "once_cell", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "oorandom" version = "11.1.5" @@ -1507,15 +1007,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "path_abs" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ef02f6342ac01d8a93b65f96db53fe68a92a15f41144f97fb00a9e669633c3" -dependencies = [ - "std_prelude", -] - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1528,25 +1019,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "plist" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d" -dependencies = [ - "base64", - "indexmap", - "quick-xml", - "serde", - "time", -] - [[package]] name = "plotters" version = "0.3.7" @@ -1575,34 +1047,6 @@ dependencies = [ "plotters-backend", ] -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - [[package]] name = "proc-macro2" version = "1.0.94" @@ -1612,49 +1056,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "profiling" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" -dependencies = [ - "profiling-procmacros", -] - -[[package]] -name = "profiling-procmacros" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "qoi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - -[[package]] -name = "quick-xml" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" -dependencies = [ - "memchr", -] - [[package]] name = "quote" version = "1.0.40" @@ -1670,43 +1071,13 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.15", -] - [[package]] name = "ratatui" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" dependencies = [ - "bitflags 2.9.0", + "bitflags", "cassowary", "compact_str", "crossterm", @@ -1722,56 +1093,6 @@ dependencies = [ "unicode-width 0.2.0", ] -[[package]] -name = "rav1e" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" -dependencies = [ - "arbitrary", - "arg_enum_proc_macro", - "arrayvec", - "av1-grain", - "bitstream-io", - "built", - "cfg-if", - "interpolate_name", - "itertools 0.12.1", - "libc", - "libfuzzer-sys", - "log", - "maybe-rayon", - "new_debug_unreachable", - "noop_proc_macro", - "num-derive", - "num-traits", - "once_cell", - "paste", - "profiling", - "rand", - "rand_chacha", - "simd_helpers", - "system-deps", - "thiserror 1.0.69", - "v_frame", - "wasm-bindgen", -] - -[[package]] -name = "ravif" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" -dependencies = [ - "avif-serialize", - "imgref", - "loop9", - "quick-error", - "rav1e", - "rayon", - "rgb", -] - [[package]] name = "rayon" version = "1.10.0" @@ -1798,7 +1119,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" dependencies = [ - "bitflags 2.9.0", + "bitflags", ] [[package]] @@ -1844,6 +1165,12 @@ dependencies = [ "regex-syntax 0.8.5", ] +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + [[package]] name = "regex-syntax" version = "0.6.29" @@ -1856,15 +1183,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "rgb" -version = "0.8.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" -dependencies = [ - "bytemuck", -] - [[package]] name = "roff" version = "0.2.2" @@ -1889,7 +1207,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.0", + "bitflags", "errno", "libc", "linux-raw-sys 0.4.15", @@ -1902,7 +1220,7 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ - "bitflags 2.9.0", + "bitflags", "errno", "libc", "linux-raw-sys 0.9.4", @@ -1936,12 +1254,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "semver" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" - [[package]] name = "serde" version = "1.0.219" @@ -1983,42 +1295,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_with" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" -dependencies = [ - "serde", - "serde_derive", - "serde_with_macros", -] - -[[package]] -name = "serde_with_macros" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -2028,12 +1304,6 @@ dependencies = [ "lazy_static", ] -[[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" @@ -2064,21 +1334,6 @@ dependencies = [ "libc", ] -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "simd_helpers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" -dependencies = [ - "quote", -] - [[package]] name = "simdutf8" version = "0.1.5" @@ -2107,12 +1362,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "std_prelude" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8207e78455ffdf55661170876f88daf85356e4edd54e0a3dbc79586ca1e50cbe" - [[package]] name = "strsim" version = "0.11.1" @@ -2152,53 +1401,13 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "syntect" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" -dependencies = [ - "bincode", - "bitflags 1.3.2", - "fancy-regex", - "flate2", - "fnv", - "once_cell", - "onig", - "regex-syntax 0.8.5", - "serde", - "serde_derive", - "serde_json", - "thiserror 1.0.69", - "walkdir", -] - -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck", - "pkg-config", - "toml", - "version-compare", -] - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - [[package]] name = "television" version = "0.11.9" dependencies = [ + "ansi-to-tui", "anyhow", "base64", - "bat", "better-panic", "clap", "clap_mangen", @@ -2207,24 +1416,16 @@ dependencies = [ "crossterm", "devicons", "directories", - "gag", "human-panic", - "image", - "nom", + "lazy-regex", "nucleo", "parking_lot", "ratatui", - "regex", "rustc-hash", "serde", "signal-hook", - "simdutf8", - "smallvec", - "strum", - "syntect", "television-derive", "tempfile", - "thiserror 2.0.12", "tokio", "toml", "tracing", @@ -2255,32 +1456,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "terminal-colorsaurus" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7afe4c174a3cbfb52ebcb11b28965daf74fe9111d4e07e40689d05af06e26e8" -dependencies = [ - "cfg-if", - "libc", - "memchr", - "mio", - "terminal-trx", - "windows-sys 0.59.0", - "xterm-color", -] - -[[package]] -name = "terminal-trx" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975b4233aefa1b02456d5e53b22c61653c743e308c51cf4181191d8ce41753ab" -dependencies = [ - "cfg-if", - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -2331,48 +1506,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tiff" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" -dependencies = [ - "flate2", - "jpeg-decoder", - "weezl", -] - -[[package]] -name = "time" -version = "0.3.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" - -[[package]] -name = "time-macros" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tinytemplate" version = "1.2.1" @@ -2418,7 +1551,6 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ - "indexmap", "serde", "serde_spanned", "toml_datetime", @@ -2497,7 +1629,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", - "nu-ansi-term 0.46.0", + "nu-ansi-term", "once_cell", "regex", "sharded-slab", @@ -2543,12 +1675,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - [[package]] name = "utf8parse" version = "0.2.2" @@ -2564,29 +1690,12 @@ dependencies = [ "getrandom 0.3.2", ] -[[package]] -name = "v_frame" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" -dependencies = [ - "aligned-vec", - "num-traits", - "wasm-bindgen", -] - [[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "version-compare" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - [[package]] name = "walkdir" version = "2.5.0" @@ -2680,12 +1789,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "weezl" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" - [[package]] name = "winapi" version = "0.3.9" @@ -2717,59 +1820,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" -dependencies = [ - "windows-core", - "windows-targets", -] - -[[package]] -name = "windows-core" -version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-targets", -] - -[[package]] -name = "windows-implement" -version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -2867,55 +1917,5 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", -] - -[[package]] -name = "xterm-color" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de5f056fb9dc8b7908754867544e26145767187aaac5a98495e88ad7cb8a80f" - -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zune-core" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" - -[[package]] -name = "zune-inflate" -version = "0.2.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "zune-jpeg" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" -dependencies = [ - "zune-core", + "bitflags", ] diff --git a/Cargo.toml b/Cargo.toml index f216d07..6fc61f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,19 +48,13 @@ ratatui = { version = "0.29", features = ["serde", "macros"] } better-panic = "0.3" signal-hook = "0.3" human-panic = "2.0" -strum = { version = "0.26", features = ["derive"] } -regex = "1.11" parking_lot = "0.12" -nom = "7.1" -thiserror = "2.0" -simdutf8 = { version = "0.1", optional = true } -smallvec = { version = "1.13", features = ["const_generics"] } -gag = "1.0" nucleo = "0.5" toml = "0.8" -image = "0.25" -syntect = { package = "syntect", version = "5.2", default-features = false } -bat = { package = "bat", version = "0.25", default-features = false } +lazy-regex = { version = "3.4.1", features = [ + "lite", +], default-features = false } +ansi-to-tui = "7.0.0" # target specific dependencies @@ -79,15 +73,6 @@ clipboard-win = "5.4.0" criterion = { version = "0.5", features = ["async_tokio"] } tempfile = "3.16.0" -[features] -simd = ["dep:simdutf8"] -zero-copy = [] -# Use fancy-regex for aarch64 Linux -fancy = ["syntect/regex-fancy", "bat/regex-fancy"] -# Use oniguruma for other platforms -onig = ["syntect/regex-onig", "bat/regex-onig"] -default = ["zero-copy", "simd", "onig"] - [build-dependencies] clap = { version = "4.5", features = ["derive", "cargo"] } diff --git a/benches/main/ui.rs b/benches/main/ui.rs index 5be7f17..73e081f 100644 --- a/benches/main/ui.rs +++ b/benches/main/ui.rs @@ -8,13 +8,13 @@ use ratatui::prelude::{Line, Style}; use ratatui::style::Color; use ratatui::widgets::{Block, BorderType, Borders, ListDirection, Padding}; use ratatui::Terminal; +use television::channels::cable::prototypes::CableChannelPrototypes; use television::{ action::Action, channels::{ cable::prototypes::CableChannelPrototype, entry::{into_ranges, Entry}, - preview::PreviewType, - OnAir, TelevisionChannel, + OnAir, }, config::{Config, ConfigEnv}, screen::{colors::ResultsColorscheme, results::build_results_list}, @@ -37,7 +37,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#7e8e91", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/README.md".to_string(), @@ -49,7 +48,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#dddddd", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/re.pyi".to_string(), @@ -61,7 +59,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/io.pyi".to_string(), @@ -73,7 +70,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/gc.pyi".to_string(), @@ -85,7 +81,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/uu.pyi".to_string(), @@ -97,7 +92,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/nt.pyi".to_string(), @@ -109,7 +103,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/dis.pyi".to_string(), @@ -121,7 +114,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/imp.pyi".to_string(), @@ -133,7 +125,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/bdb.pyi".to_string(), @@ -145,7 +136,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/abc.pyi".to_string(), @@ -157,7 +147,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/cgi.pyi".to_string(), @@ -169,7 +158,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/bz2.pyi".to_string(), @@ -181,7 +169,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/grp.pyi".to_string(), @@ -193,7 +180,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/ast.pyi".to_string(), @@ -205,7 +191,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/csv.pyi".to_string(), @@ -217,7 +202,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/pdb.pyi".to_string(), @@ -229,7 +213,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/pwd.pyi".to_string(), @@ -241,7 +224,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/ssl.pyi".to_string(), @@ -253,7 +235,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/tty.pyi".to_string(), @@ -265,7 +246,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/nis.pyi".to_string(), @@ -277,7 +257,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/pty.pyi".to_string(), @@ -289,7 +268,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/cmd.pyi".to_string(), @@ -301,7 +279,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/tests/utils.py".to_string(), @@ -313,7 +290,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/pyproject.toml".to_string(), @@ -325,7 +301,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#9c4221", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/MAINTAINERS.md".to_string(), @@ -337,7 +312,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#dddddd", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/enum.pyi".to_string(), @@ -349,7 +323,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/hmac.pyi".to_string(), @@ -361,7 +334,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/uuid.pyi".to_string(), @@ -373,7 +345,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/glob.pyi".to_string(), @@ -385,7 +356,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/_ast.pyi".to_string(), @@ -397,7 +367,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/_csv.pyi".to_string(), @@ -409,7 +378,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/code.pyi".to_string(), @@ -421,7 +389,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/spwd.pyi".to_string(), @@ -433,7 +400,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/_msi.pyi".to_string(), @@ -445,7 +411,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/time.pyi".to_string(), @@ -456,7 +421,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])), value_match_ranges: None, }, @@ -508,14 +472,19 @@ pub fn draw(c: &mut Criterion) { let backend = TestBackend::new(width, height); let terminal = Terminal::new(backend).unwrap(); let (tx, _) = tokio::sync::mpsc::unbounded_channel(); - let mut channel = TelevisionChannel::Cable( - CableChannelPrototype::default().into(), - ); - channel.find("television"); + let channel = CableChannelPrototype::default(); // Wait for the channel to finish loading let mut tv = Television::new( - tx, channel, config, None, false, false, false, + tx, + channel, + config, + None, + false, + false, + false, + CableChannelPrototypes::default(), ); + tv.find("television"); for _ in 0..5 { // tick the matcher let _ = tv.channel.results(10, 0); diff --git a/cable/unix-channels.toml b/cable/unix-channels.toml index fdc25a1..b98b885 100644 --- a/cable/unix-channels.toml +++ b/cable/unix-channels.toml @@ -2,7 +2,7 @@ [[cable_channel]] name = "files" source_command = "fd -t f" -preview_command = ":files:" +preview_command = "bat -n --color=always {}" # Text [[cable_channel]] @@ -72,7 +72,7 @@ preview_command = "aws s3 ls s3://{0}" [[cable_channel]] name = "my-dotfiles" source_command = "fd -t f . $HOME/.config" -preview_command = ":files:" +preview_command = "bat -n --color=always {}" # Shell history [[cable_channel]] diff --git a/cable/windows-channels.toml b/cable/windows-channels.toml index cb512f4..2dbfcde 100644 --- a/cable/windows-channels.toml +++ b/cable/windows-channels.toml @@ -2,13 +2,13 @@ [[cable_channel]] name = "files" source_command = "Get-ChildItem -Recurse -File | Select-Object -ExpandProperty FullName" -preview_command = ":files:" +preview_command = "bat -n --color=always {}" # Directories [[cable_channel]] name = "dirs" source_command = "Get-ChildItem -Recurse -Directory | Select-Object -ExpandProperty FullName" -preview_command = "ls -l {0}" +preview_command = "ls -l {}" # Environment variables [[cable_channel]] @@ -29,7 +29,7 @@ preview_command = "cd '{}' ; git log -n 200 --pretty=medium --all --graph --colo [[cable_channel]] name = "git-diff" source_command = "git diff --name-only" -preview_command = "git diff --color=always {0}" +preview_command = "git diff --color=always {}" [[cable_channel]] name = "git-reflog" @@ -56,7 +56,7 @@ preview_command = "docker image inspect {0} | jq -C" [[cable_channel]] name = "my-dotfiles" source_command = "Get-ChildItem -Recurse -File -Path \"$env:USERPROFILE\\AppData\\Roaming\\\"" -preview_command = ":files:" +preview_command = "bat -n --color=always {}" # Shell history [[cable_channel]] diff --git a/television/app.rs b/television/app.rs index b7554c2..e9f7def 100644 --- a/television/app.rs +++ b/television/app.rs @@ -4,9 +4,10 @@ use anyhow::Result; use tokio::sync::mpsc; use tracing::{debug, trace}; -use crate::channels::{ - entry::Entry, preview::PreviewType, OnAir, TelevisionChannel, +use crate::channels::cable::prototypes::{ + CableChannelPrototype, CableChannelPrototypes, }; +use crate::channels::{entry::Entry, OnAir}; use crate::config::{default_tick_rate, Config}; use crate::keymap::Keymap; use crate::render::UiState; @@ -123,7 +124,6 @@ impl From for AppOutput { ActionOutcome::Input(input) => Self { selected_entries: Some(FxHashSet::from_iter([Entry::new( input, - PreviewType::None, )])), }, ActionOutcome::None => Self { @@ -138,10 +138,11 @@ const ACTION_BUF_SIZE: usize = 8; impl App { pub fn new( - channel: TelevisionChannel, + channel_prototype: CableChannelPrototype, config: Config, input: Option, options: AppOptions, + cable_channels: &CableChannelPrototypes, ) -> Self { let (action_tx, action_rx) = mpsc::unbounded_channel(); let (render_tx, render_rx) = mpsc::unbounded_channel(); @@ -153,12 +154,13 @@ impl App { let (ui_state_tx, ui_state_rx) = mpsc::unbounded_channel(); let television = Television::new( action_tx.clone(), - channel, + channel_prototype, config, input, options.no_remote, options.no_help, options.exact, + CableChannelPrototypes((*cable_channels).clone()), ); Self { @@ -201,7 +203,7 @@ impl App { // Event loop if !headless { debug!("Starting backend event loop"); - let event_loop = EventLoop::new(self.options.tick_rate, true); + let event_loop = EventLoop::new(self.options.tick_rate); self.event_rx = event_loop.rx; self.event_abort_tx = event_loop.abort_tx; } @@ -436,32 +438,3 @@ impl App { None } } - -#[cfg(test)] -mod test { - use super::*; - use crate::channels::stdin::Channel as StdinChannel; - - #[test] - fn test_maybe_select_1() { - let mut app = App::new( - TelevisionChannel::Stdin(StdinChannel::new(PreviewType::None)), - Config::default(), - None, - AppOptions::default(), - ); - app.television - .results_picker - .entries - .push(Entry::new("test".to_string(), PreviewType::None)); - let outcome = app.maybe_select_1(); - assert!(outcome.is_some()); - assert_eq!( - outcome.unwrap(), - ActionOutcome::Entries(FxHashSet::from_iter([Entry::new( - "test".to_string(), - PreviewType::None - )])) - ); - } -} diff --git a/television/cable.rs b/television/cable.rs index 7c16c2e..cb3de75 100644 --- a/television/cable.rs +++ b/television/cable.rs @@ -6,7 +6,9 @@ use anyhow::Result; use tracing::{debug, error}; use crate::{ - channels::cable::prototypes::{CableChannelPrototype, CableChannels}, + channels::cable::prototypes::{ + CableChannelPrototype, CableChannelPrototypes, + }, config::get_config_dir, }; @@ -40,7 +42,7 @@ const DEFAULT_CABLE_CHANNELS: &str = /// ├── my_channels.toml /// └── windows_channels.toml /// ``` -pub fn load_cable_channels() -> Result { +pub fn load_cable_channels() -> Result { let config_dir = get_config_dir(); // list all files in the config directory @@ -95,7 +97,7 @@ pub fn load_cable_channels() -> Result { { cable_channels.insert(prototype.name.clone(), prototype); } - Ok(CableChannels(cable_channels)) + Ok(CableChannelPrototypes(cable_channels)) } fn is_cable_file_format

(p: P) -> bool diff --git a/television/channels/cable.rs b/television/channels/cable.rs index a90e9b1..ddb50d0 100644 --- a/television/channels/cable.rs +++ b/television/channels/cable.rs @@ -6,12 +6,7 @@ use prototypes::{CableChannelPrototype, DEFAULT_DELIMITER}; use rustc_hash::{FxBuildHasher, FxHashSet}; use tracing::debug; -use crate::channels::preview::parse_preview_type; -use crate::channels::{ - entry::Entry, - preview::{PreviewCommand, PreviewType}, - OnAir, -}; +use crate::channels::{entry::Entry, preview::PreviewCommand, OnAir}; use crate::matcher::Matcher; use crate::matcher::{config::Config, injector::Injector}; use crate::utils::command::shell_command; @@ -23,7 +18,7 @@ pub struct Channel { pub name: String, matcher: Matcher, entries_command: String, - preview_type: PreviewType, + pub preview_command: Option, selected_entries: FxHashSet, crawl_handle: tokio::task::JoinHandle<()>, } @@ -34,7 +29,7 @@ impl Default for Channel { "files", "find . -type f", false, - Some(PreviewCommand::new("cat {}", ":")), + Some(PreviewCommand::new("cat {}", ":", None)), ) } } @@ -51,6 +46,7 @@ impl From for Channel { &prototype .preview_delimiter .unwrap_or(DEFAULT_DELIMITER.to_string()), + prototype.preview_offset, )), None => None, }, @@ -72,19 +68,10 @@ impl Channel { interactive, injector, )); - let preview_kind = match preview_command { - Some(command) => { - parse_preview_type(&command).unwrap_or_else(|_| { - panic!("Invalid preview command: {command}") - }) - } - None => PreviewType::None, - }; - debug!("Preview kind: {:?}", preview_kind); Self { matcher, entries_command: entries_command.to_string(), - preview_type: preview_kind, + preview_command, name: name.to_string(), selected_entries: HashSet::with_hasher(FxBuildHasher), crawl_handle, @@ -149,8 +136,7 @@ impl OnAir for Channel { .into_iter() .map(|item| { let path = item.matched_string; - Entry::new(path, self.preview_type.clone()) - .with_name_match_indices(&item.match_indices) + Entry::new(path).with_name_match_indices(&item.match_indices) }) .collect() } @@ -158,7 +144,7 @@ impl OnAir for Channel { fn get_result(&self, index: u32) -> Option { self.matcher.get_result(index).map(|item| { let path = item.matched_string; - Entry::new(path, self.preview_type.clone()) + Entry::new(path) }) } @@ -189,6 +175,6 @@ impl OnAir for Channel { fn shutdown(&self) {} fn supports_preview(&self) -> bool { - self.preview_type != PreviewType::None + self.preview_command.is_some() } } diff --git a/television/channels/cable/prototypes.rs b/television/channels/cable/prototypes.rs index e5f139b..b3bd108 100644 --- a/television/channels/cable/prototypes.rs +++ b/television/channels/cable/prototypes.rs @@ -4,7 +4,9 @@ use std::{ ops::Deref, }; -use crate::cable::SerializedChannelPrototypes; +use crate::{ + cable::SerializedChannelPrototypes, channels::preview::PreviewCommand, +}; /// A prototype for a cable channel. /// @@ -35,7 +37,7 @@ use crate::cable::SerializedChannelPrototypes; /// [[cable_channel]] /// name = "files" /// source_command = "fd -t f" -/// preview_command = ":files:" +/// preview_command = "cat {}" /// ``` #[derive(Clone, Debug, serde::Deserialize, PartialEq)] pub struct CableChannelPrototype { @@ -49,6 +51,9 @@ pub struct CableChannelPrototype { pub preview_offset: Option, } +const STDIN_CHANNEL_NAME: &str = "stdin"; +const STDIN_SOURCE_COMMAND: &str = "cat"; + impl CableChannelPrototype { pub fn new( name: &str, @@ -67,23 +72,42 @@ impl CableChannelPrototype { preview_offset, } } + + pub fn stdin(preview: Option) -> Self { + match preview { + Some(PreviewCommand { + command, + delimiter, + offset_expr, + }) => Self { + name: STDIN_CHANNEL_NAME.to_string(), + source_command: STDIN_SOURCE_COMMAND.to_string(), + interactive: false, + preview_command: Some(command), + preview_delimiter: Some(delimiter), + preview_offset: offset_expr, + }, + None => Self { + name: STDIN_CHANNEL_NAME.to_string(), + source_command: STDIN_SOURCE_COMMAND.to_string(), + interactive: false, + preview_command: None, + preview_delimiter: None, + preview_offset: None, + }, + } + } } const DEFAULT_PROTOTYPE_NAME: &str = "files"; -const DEFAULT_SOURCE_COMMAND: &str = "fd -t f"; -const DEFAULT_PREVIEW_COMMAND: &str = ":files:"; pub const DEFAULT_DELIMITER: &str = " "; impl Default for CableChannelPrototype { fn default() -> Self { - Self { - name: DEFAULT_PROTOTYPE_NAME.to_string(), - source_command: DEFAULT_SOURCE_COMMAND.to_string(), - interactive: false, - preview_command: Some(DEFAULT_PREVIEW_COMMAND.to_string()), - preview_delimiter: Some(DEFAULT_DELIMITER.to_string()), - preview_offset: None, - } + CableChannelPrototypes::default() + .get(DEFAULT_PROTOTYPE_NAME) + .cloned() + .unwrap() } } @@ -106,9 +130,11 @@ impl Display for CableChannelPrototype { /// in a way that facilitates answering questions like "what's the prototype /// for `files`?" or "does this channel exist?". #[derive(Debug, serde::Deserialize)] -pub struct CableChannels(pub FxHashMap); +pub struct CableChannelPrototypes( + pub FxHashMap, +); -impl Deref for CableChannels { +impl Deref for CableChannelPrototypes { type Target = FxHashMap; fn deref(&self) -> &Self::Target { @@ -125,20 +151,20 @@ const DEFAULT_CABLE_CHANNELS_FILE: &str = /// application. #[cfg(not(unix))] const DEFAULT_CABLE_CHANNELS_FILE: &str = - include_str!("../../cable/windows-channels.toml"); + include_str!("../../../cable/windows-channels.toml"); -impl Default for CableChannels { +impl Default for CableChannelPrototypes { /// Fallback to the default cable channels specification (the template file /// included in the repo). fn default() -> Self { - let pts = toml::from_str::( + let s = toml::from_str::( DEFAULT_CABLE_CHANNELS_FILE, ) .expect("Unable to parse default cable channels"); - let mut channels = FxHashMap::default(); - for prototype in pts.prototypes { - channels.insert(prototype.name.clone(), prototype); + let mut prototypes = FxHashMap::default(); + for prototype in s.prototypes { + prototypes.insert(prototype.name.clone(), prototype); } - CableChannels(channels) + CableChannelPrototypes(prototypes) } } diff --git a/television/channels/entry.rs b/television/channels/entry.rs index 9f95ad8..68c65b5 100644 --- a/television/channels/entry.rs +++ b/television/channels/entry.rs @@ -2,8 +2,6 @@ use std::hash::{Hash, Hasher}; use devicons::FileIcon; -use crate::channels::preview::PreviewType; - // NOTE: having an enum for entry types would be nice since it would allow // having a nicer implementation for transitions between channels. This would // permit implementing `From` for channels which would make the @@ -24,8 +22,6 @@ pub struct Entry { pub icon: Option, /// The optional line number associated with the entry. pub line_number: Option, - /// The type of preview associated with the entry. - pub preview_type: PreviewType, } impl Hash for Entry { @@ -85,10 +81,10 @@ impl Entry { /// /// Additional fields can be set using the builder pattern. /// ``` - /// use television::channels::{entry::Entry, preview::PreviewType}; + /// use television::channels::entry::Entry; /// use devicons::FileIcon; /// - /// let entry = Entry::new("name".to_string(), PreviewType::EnvVar) + /// let entry = Entry::new("name".to_string()) /// .with_value("value".to_string()) /// .with_name_match_indices(&vec![0]) /// .with_value_match_indices(&vec![0]) @@ -98,12 +94,11 @@ impl Entry { /// /// # Arguments /// * `name` - The name of the entry. - /// * `preview_type` - The type of preview associated with the entry. /// /// # Returns /// A new entry with the given name and preview type. /// The other fields are set to `None` by default. - pub fn new(name: String, preview_type: PreviewType) -> Self { + pub fn new(name: String) -> Self { Self { name, value: None, @@ -111,7 +106,6 @@ impl Entry { value_match_ranges: None, icon: None, line_number: None, - preview_type, } } @@ -149,16 +143,6 @@ impl Entry { } } -pub const ENTRY_PLACEHOLDER: Entry = Entry { - name: String::new(), - value: None, - name_match_ranges: None, - value_match_ranges: None, - icon: None, - line_number: None, - preview_type: PreviewType::EnvVar, -}; - #[cfg(test)] mod tests { use super::*; @@ -196,7 +180,6 @@ mod tests { value_match_ranges: None, icon: None, line_number: None, - preview_type: PreviewType::Basic, }; assert_eq!(entry.stdout_repr(), "test name with spaces"); } @@ -210,7 +193,6 @@ mod tests { value_match_ranges: None, icon: None, line_number: Some(a), - preview_type: PreviewType::Basic, }; assert_eq!(entry.stdout_repr(), "test_file_name.rs:10"); } diff --git a/television/channels/mod.rs b/television/channels/mod.rs index 7eec13f..a49887a 100644 --- a/television/channels/mod.rs +++ b/television/channels/mod.rs @@ -1,5 +1,6 @@ use crate::channels::entry::Entry; use anyhow::Result; +use cable::prototypes::CableChannelPrototype; use rustc_hash::FxHashSet; use television_derive::Broadcast; @@ -7,7 +8,6 @@ pub mod cable; pub mod entry; pub mod preview; pub mod remote_control; -pub mod stdin; /// The interface that all television channels must implement. /// @@ -115,10 +115,6 @@ pub trait OnAir: Send { #[allow(dead_code, clippy::module_name_repetitions)] #[derive(Broadcast)] pub enum TelevisionChannel { - /// The standard input channel. - /// - /// This channel allows to search through whatever is passed through stdin. - Stdin(stdin::Channel), /// The remote control channel. /// /// This channel allows to switch between different channels. @@ -130,19 +126,18 @@ pub enum TelevisionChannel { } impl TelevisionChannel { - pub fn zap(&self, channel_name: &str) -> Result { + pub fn zap(&self, channel_name: &str) -> Result { match self { TelevisionChannel::RemoteControl(remote_control) => { remote_control.zap(channel_name) } - _ => unreachable!(), + TelevisionChannel::Cable(_) => unreachable!(), } } pub fn name(&self) -> String { match self { TelevisionChannel::Cable(channel) => channel.name.clone(), - TelevisionChannel::Stdin(_) => String::from("Stdin"), TelevisionChannel::RemoteControl(_) => String::from("Remote"), } } diff --git a/television/channels/preview.rs b/television/channels/preview.rs index bc1c303..70b4fe9 100644 --- a/television/channels/preview.rs +++ b/television/channels/preview.rs @@ -1,21 +1,86 @@ use std::fmt::Display; -use anyhow::Result; -use regex::Regex; -use strum::EnumString; +use super::{cable::prototypes::DEFAULT_DELIMITER, entry::Entry}; +use crate::channels::cable::prototypes::CableChannelPrototype; +use lazy_regex::{regex, Lazy, Regex}; use tracing::debug; +static CMD_RE: &Lazy = regex!(r"\{(\d+)\}"); + #[derive(Debug, Clone, Eq, PartialEq, Hash, Default)] pub struct PreviewCommand { pub command: String, pub delimiter: String, + pub offset_expr: Option, } impl PreviewCommand { - pub fn new(command: &str, delimiter: &str) -> Self { + pub fn new( + command: &str, + delimiter: &str, + offset_expr: Option, + ) -> Self { Self { command: command.to_string(), delimiter: delimiter.to_string(), + offset_expr, + } + } + + /// Format the command with the entry name and provided placeholders. + /// + /// # Example + /// ``` + /// use television::channels::{preview::PreviewCommand, entry::Entry}; + /// + /// let command = PreviewCommand { + /// command: "something {} {2} {0}".to_string(), + /// delimiter: ":".to_string(), + /// offset_expr: None, + /// }; + /// let entry = Entry::new("a:given:entry:to:preview".to_string()); + /// + /// let formatted_command = command.format_with(&entry); + /// + /// assert_eq!(formatted_command, "something 'a:given:entry:to:preview' 'entry' 'a'"); + /// ``` + pub fn format_with(&self, entry: &Entry) -> String { + let parts = entry.name.split(&self.delimiter).collect::>(); + + let mut formatted_command = self + .command + .replace("{}", format!("'{}'", entry.name).as_str()); + debug!("FORMATTED_COMMAND: {formatted_command}"); + debug!("PARTS: {parts:?}"); + + formatted_command = CMD_RE + .replace_all(&formatted_command, |caps: ®ex::Captures| { + let index = + caps.get(1).unwrap().as_str().parse::().unwrap(); + format!("'{}'", parts[index]) + }) + .to_string(); + + formatted_command + } +} + +impl From<&CableChannelPrototype> for Option { + fn from(value: &CableChannelPrototype) -> Self { + if let Some(command) = value.preview_command.as_ref() { + let delimiter = value + .preview_delimiter + .as_ref() + .map_or(DEFAULT_DELIMITER, |v| v); + + let offset_expr = value.preview_offset.clone(); + + // FIXME: handle offset here (side note: we don't want to reparse the offset + // expression for each entry, so maybe just parse it once and try to store it + // as some sort of function we can call later on + Some(PreviewCommand::new(command, delimiter, offset_expr)) + } else { + None } } } @@ -26,38 +91,63 @@ impl Display for PreviewCommand { } } -#[derive(Debug, Clone, Eq, PartialEq, Hash, Default, EnumString)] -#[strum(serialize_all = "snake_case")] -pub enum PreviewType { - Basic, - EnvVar, - Files, - #[strum(disabled)] - Command(PreviewCommand), - #[default] - None, -} +#[cfg(test)] +mod tests { + use super::*; + use crate::channels::entry::Entry; -/// Parses the preview command to determine the preview type. -/// -/// This checks if the command matches the builtin pattern `:{preview_type}:` -/// and then falls back to the command type if it doesn't. -/// -/// # Example: -/// ``` -/// use television::channels::preview::{parse_preview_type, PreviewCommand, PreviewType}; -/// -/// let command = PreviewCommand::new("cat {0}", ":"); -/// let preview_type = parse_preview_type(&command).unwrap(); -/// assert_eq!(preview_type, PreviewType::Command(command)); -/// ``` -pub fn parse_preview_type(command: &PreviewCommand) -> Result { - debug!("Parsing preview kind for command: {:?}", command); - let re = Regex::new(r"^\:(\w+)\:$").unwrap(); - if let Some(captures) = re.captures(&command.command) { - let preview_type = PreviewType::try_from(&captures[1])?; - Ok(preview_type) - } else { - Ok(PreviewType::Command(command.clone())) + #[test] + fn test_format_command() { + let command = PreviewCommand { + command: "something {} {2} {0}".to_string(), + delimiter: ":".to_string(), + offset_expr: None, + }; + let entry = Entry::new("an:entry:to:preview".to_string()); + let formatted_command = command.format_with(&entry); + + assert_eq!( + formatted_command, + "something 'an:entry:to:preview' 'to' 'an'" + ); + } + + #[test] + fn test_format_command_no_placeholders() { + let command = PreviewCommand { + command: "something".to_string(), + delimiter: ":".to_string(), + offset_expr: None, + }; + let entry = Entry::new("an:entry:to:preview".to_string()); + let formatted_command = command.format_with(&entry); + + assert_eq!(formatted_command, "something"); + } + + #[test] + fn test_format_command_with_global_placeholder_only() { + let command = PreviewCommand { + command: "something {}".to_string(), + delimiter: ":".to_string(), + offset_expr: None, + }; + let entry = Entry::new("an:entry:to:preview".to_string()); + let formatted_command = command.format_with(&entry); + + assert_eq!(formatted_command, "something 'an:entry:to:preview'"); + } + + #[test] + fn test_format_command_with_positional_placeholders_only() { + let command = PreviewCommand { + command: "something {0} -t {2}".to_string(), + delimiter: ":".to_string(), + offset_expr: None, + }; + let entry = Entry::new("an:entry:to:preview".to_string()); + let formatted_command = command.format_with(&entry); + + assert_eq!(formatted_command, "something 'an' -t 'to'"); } } diff --git a/television/channels/remote_control.rs b/television/channels/remote_control.rs index 01cdd4b..5cf95f0 100644 --- a/television/channels/remote_control.rs +++ b/television/channels/remote_control.rs @@ -1,30 +1,30 @@ use std::collections::HashSet; -use crate::channels::cable::prototypes::CableChannels; -use crate::channels::{entry::Entry, preview::PreviewType}; -use crate::channels::{OnAir, TelevisionChannel}; +use crate::channels::cable::prototypes::CableChannelPrototypes; +use crate::channels::entry::Entry; +use crate::channels::OnAir; use crate::matcher::{config::Config, Matcher}; use anyhow::Result; use devicons::FileIcon; use rustc_hash::{FxBuildHasher, FxHashSet}; -use super::cable; +use super::cable::prototypes::CableChannelPrototype; pub struct RemoteControl { matcher: Matcher, - cable_channels: Option, + cable_channels: Option, selected_entries: FxHashSet, } const NUM_THREADS: usize = 1; impl RemoteControl { - pub fn new(cable_channels: Option) -> Self { + pub fn new(cable_channels: Option) -> Self { let matcher = Matcher::new(Config::default().n_threads(NUM_THREADS)); let injector = matcher.injector(); for c in cable_channels .as_ref() - .unwrap_or(&CableChannels::default()) + .unwrap_or(&CableChannelPrototypes::default()) .keys() { let () = injector.push(c.clone(), |e, cols| { @@ -38,15 +38,13 @@ impl RemoteControl { } } - pub fn zap(&self, channel_name: &str) -> Result { + pub fn zap(&self, channel_name: &str) -> Result { match self .cable_channels .as_ref() .and_then(|channels| channels.get(channel_name).cloned()) { - Some(prototype) => { - Ok(TelevisionChannel::Cable(cable::Channel::from(prototype))) - } + Some(prototype) => Ok(prototype), None => Err(anyhow::anyhow!( "No channel or cable channel prototype found for {}", channel_name @@ -83,7 +81,7 @@ impl OnAir for RemoteControl { .into_iter() .map(|item| { let path = item.matched_string; - Entry::new(path, PreviewType::Basic) + Entry::new(path) .with_name_match_indices(&item.match_indices) .with_icon(CABLE_ICON) }) @@ -93,7 +91,7 @@ impl OnAir for RemoteControl { fn get_result(&self, index: u32) -> Option { self.matcher.get_result(index).map(|item| { let path = item.matched_string; - Entry::new(path, PreviewType::Basic).with_icon(TV_ICON) + Entry::new(path).with_icon(TV_ICON) }) } diff --git a/television/channels/stdin.rs b/television/channels/stdin.rs deleted file mode 100644 index cf97b9b..0000000 --- a/television/channels/stdin.rs +++ /dev/null @@ -1,156 +0,0 @@ -use std::{ - collections::HashSet, - io::{stdin, BufRead}, - thread::spawn, -}; - -use rustc_hash::{FxBuildHasher, FxHashSet}; -use tracing::debug; - -use super::OnAir; -use crate::channels::{entry::Entry, preview::PreviewType}; -use crate::matcher::{config::Config, injector::Injector, Matcher}; - -pub struct Channel { - matcher: Matcher, - preview_type: PreviewType, - selected_entries: FxHashSet, - instream_handle: std::thread::JoinHandle<()>, -} - -impl Channel { - pub fn new(preview_type: PreviewType) -> Self { - let matcher = Matcher::new(Config::default()); - let injector = matcher.injector(); - - let instream_handle = spawn(move || stream_from_stdin(&injector)); - - Self { - matcher, - preview_type, - selected_entries: HashSet::with_hasher(FxBuildHasher), - instream_handle, - } - } -} - -impl Default for Channel { - fn default() -> Self { - Self::new(PreviewType::default()) - } -} - -impl From for Channel -where - E: AsRef>, -{ - fn from(entries: E) -> Self { - let matcher = Matcher::new(Config::default()); - let injector = matcher.injector(); - - let entries = entries.as_ref().clone(); - - let instream_handle = spawn(move || { - for entry in entries { - injector.push(entry.clone(), |e, cols| { - cols[0] = e.to_string().into(); - }); - } - }); - - Self { - matcher, - preview_type: PreviewType::default(), - selected_entries: HashSet::with_hasher(FxBuildHasher), - instream_handle, - } - } -} - -const TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); - -fn stream_from_stdin(injector: &Injector) { - let mut stdin = stdin().lock(); - let mut buffer = String::new(); - - let instant = std::time::Instant::now(); - loop { - match stdin.read_line(&mut buffer) { - Ok(c) if c > 0 => { - let trimmed = buffer.trim(); - if !trimmed.is_empty() { - injector.push(trimmed.to_owned(), |e, cols| { - cols[0] = e.clone().into(); - }); - } - buffer.clear(); - } - Ok(0) => { - debug!("EOF"); - break; - } - _ => { - debug!("Error reading from stdin"); - if instant.elapsed() > TIMEOUT { - break; - } - } - } - } -} - -impl OnAir for Channel { - fn find(&mut self, pattern: &str) { - self.matcher.find(pattern); - } - - fn results(&mut self, num_entries: u32, offset: u32) -> Vec { - self.matcher.tick(); - self.matcher - .results(num_entries, offset) - .into_iter() - .map(|item| { - // NOTE: we're passing `PreviewType::Basic` here just as a placeholder - // to avoid storing the preview command multiple times for each item. - Entry::new(item.matched_string, PreviewType::Basic) - .with_name_match_indices(&item.match_indices) - }) - .collect() - } - - fn get_result(&self, index: u32) -> Option { - self.matcher.get_result(index).map(|item| { - Entry::new(item.matched_string, self.preview_type.clone()) - }) - } - - fn selected_entries(&self) -> &FxHashSet { - &self.selected_entries - } - - fn toggle_selection(&mut self, entry: &Entry) { - if self.selected_entries.contains(entry) { - self.selected_entries.remove(entry); - } else { - self.selected_entries.insert(entry.clone()); - } - } - - fn result_count(&self) -> u32 { - self.matcher.matched_item_count - } - - fn total_count(&self) -> u32 { - self.matcher.total_item_count - } - - fn running(&self) -> bool { - self.matcher.status.running || !self.instream_handle.is_finished() - } - - fn shutdown(&self) {} - - fn supports_preview(&self) -> bool { - self.preview_type != PreviewType::None - } -} diff --git a/television/cli/args.rs b/television/cli/args.rs index eb44b0d..f61d1d3 100644 --- a/television/cli/args.rs +++ b/television/cli/args.rs @@ -12,12 +12,11 @@ pub struct Cli { #[arg(value_enum, index = 1, verbatim_doc_comment)] pub channel: Option, - /// A preview command to use with the stdin channel. + /// A preview command to use with the current channel. /// /// If provided, the preview command will be executed and formatted using /// the entry. - /// Example: "bat -n --color=always {}" (where {} will be replaced with - /// the entry) + /// Example: "cat {}" (where {} will be replaced with the entry) /// /// Parts of the entry can be extracted positionally using the `delimiter` /// option. diff --git a/television/cli/mod.rs b/television/cli/mod.rs index 4d8056b..5c5ae82 100644 --- a/television/cli/mod.rs +++ b/television/cli/mod.rs @@ -5,11 +5,9 @@ use anyhow::{anyhow, Result}; use tracing::debug; use crate::channels::cable::prototypes::{ - CableChannelPrototype, CableChannels, -}; -use crate::channels::preview::{ - parse_preview_type, PreviewCommand, PreviewType, + CableChannelPrototype, CableChannelPrototypes, }; +use crate::channels::preview::PreviewCommand; use crate::cli::args::{Cli, Command}; use crate::config::{KeyBindings, DEFAULT_CHANNEL}; use crate::{ @@ -23,7 +21,7 @@ pub mod args; #[derive(Debug, Clone)] pub struct PostProcessedCli { pub channel: CableChannelPrototype, - pub preview_kind: PreviewType, + pub preview_command: Option, pub no_preview: bool, pub tick_rate: Option, pub frame_rate: Option, @@ -44,7 +42,7 @@ impl Default for PostProcessedCli { fn default() -> Self { Self { channel: CableChannelPrototype::default(), - preview_kind: PreviewType::None, + preview_command: None, no_preview: false, tick_rate: None, frame_rate: None, @@ -75,21 +73,14 @@ impl From for PostProcessedCli { }); // parse the preview command if provided - let preview_kind = cli - .preview - .map(|preview| PreviewCommand { - command: preview, - delimiter: cli.delimiter.clone(), - }) - .map_or(PreviewType::None, |preview_command| { - parse_preview_type(&preview_command) - .map_err(|e| { - cli_parsing_error_exit(&e.to_string()); - }) - .unwrap() - }); + let preview_command = cli.preview.map(|preview| PreviewCommand { + command: preview, + delimiter: cli.delimiter.clone(), + // TODO: add the --preview-offset option to the CLI + offset_expr: None, + }); - let channel: CableChannelPrototype; + let mut channel: CableChannelPrototype; let working_directory: Option; let cable_channels = cable::load_cable_channels().unwrap_or_default(); @@ -127,9 +118,15 @@ impl From for PostProcessedCli { } } + if let Some(preview_cmd) = &preview_command { + channel.preview_command = Some(preview_cmd.command.clone()); + channel.preview_delimiter = Some(preview_cmd.delimiter.clone()); + channel.preview_offset.clone_from(&preview_cmd.offset_expr); + } + Self { channel, - preview_kind, + preview_command, no_preview: cli.no_preview, tick_rate: cli.tick_rate, frame_rate: cli.frame_rate, @@ -181,7 +178,7 @@ fn parse_keybindings_literal( pub fn parse_channel( channel: &str, - cable_channels: &CableChannels, + cable_channels: &CableChannelPrototypes, ) -> Result { // try to parse the channel as a cable channel match cable_channels @@ -226,7 +223,7 @@ pub fn guess_channel_from_prompt( prompt: &str, command_mapping: &FxHashMap, fallback_channel: &str, - cable_channels: &CableChannels, + cable_channels: &CableChannelPrototypes, ) -> Result { debug!("Guessing channel from prompt: {}", prompt); // git checkout -qf @@ -303,10 +300,7 @@ Data directory: {data_dir_path}" #[cfg(test)] mod tests { - use crate::{ - action::Action, channels::preview::PreviewType, config::Binding, - event::Key, - }; + use crate::{action::Action, config::Binding, event::Key}; use super::*; @@ -323,15 +317,18 @@ mod tests { let post_processed_cli: PostProcessedCli = cli.into(); + let expected = CableChannelPrototype { + preview_delimiter: Some(":".to_string()), + ..Default::default() + }; + + assert_eq!(post_processed_cli.channel, expected,); assert_eq!( - post_processed_cli.channel, - CableChannelPrototype::default(), - ); - assert_eq!( - post_processed_cli.preview_kind, - PreviewType::Command(PreviewCommand { + post_processed_cli.preview_command, + Some(PreviewCommand { command: "bat -n --color=always {}".to_string(), - delimiter: ":".to_string() + delimiter: ":".to_string(), + offset_expr: None, }) ); assert_eq!(post_processed_cli.tick_rate, None); @@ -364,34 +361,6 @@ mod tests { assert_eq!(post_processed_cli.command, None); } - #[test] - fn test_builtin_previewer_files() { - let cli = Cli { - channel: Some("files".to_string()), - preview: Some(":files:".to_string()), - delimiter: ":".to_string(), - ..Default::default() - }; - - let post_processed_cli: PostProcessedCli = cli.into(); - - assert_eq!(post_processed_cli.preview_kind, PreviewType::Files); - } - - #[test] - fn test_builtin_previewer_env() { - let cli = Cli { - channel: Some("files".to_string()), - preview: Some(":env_var:".to_string()), - delimiter: ":".to_string(), - ..Default::default() - }; - - let post_processed_cli: PostProcessedCli = cli.into(); - - assert_eq!(post_processed_cli.preview_kind, PreviewType::EnvVar); - } - #[test] fn test_custom_keybindings() { let cli = Cli { @@ -419,7 +388,7 @@ mod tests { /// Returns a tuple containing a command mapping and a fallback channel. fn guess_channel_from_prompt_setup<'a>( - ) -> (FxHashMap, &'a str, CableChannels) { + ) -> (FxHashMap, &'a str, CableChannelPrototypes) { let mut command_mapping = FxHashMap::default(); command_mapping.insert("vim".to_string(), "files".to_string()); command_mapping.insert("export".to_string(), "env".to_string()); diff --git a/television/config/mod.rs b/television/config/mod.rs index 25907ba..bd3158e 100644 --- a/television/config/mod.rs +++ b/television/config/mod.rs @@ -9,7 +9,6 @@ use anyhow::{Context, Result}; use directories::ProjectDirs; pub use keybindings::merge_keybindings; pub use keybindings::{parse_key, Binding, KeyBindings}; -use previewers::PreviewersConfig; use serde::{Deserialize, Serialize}; use shell_integration::ShellIntegrationConfig; pub use themes::Theme; @@ -17,7 +16,6 @@ use tracing::{debug, warn}; pub use ui::UiConfig; mod keybindings; -mod previewers; pub mod shell_integration; mod themes; mod ui; @@ -58,7 +56,6 @@ impl Hash for AppConfig { #[allow(dead_code)] #[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, Hash)] -#[serde(deny_unknown_fields)] pub struct Config { /// General application configuration #[allow(clippy::struct_field_names)] @@ -70,9 +67,6 @@ pub struct Config { /// UI configuration #[serde(default)] pub ui: UiConfig, - /// Previewers configuration - #[serde(default)] - pub previewers: PreviewersConfig, /// Shell integration configuration #[serde(default)] pub shell_integration: ShellIntegrationConfig, @@ -201,7 +195,6 @@ impl Config { application: user.application, keybindings: user.keybindings, ui: user.ui, - previewers: user.previewers, shell_integration: user.shell_integration, } } @@ -330,7 +323,6 @@ mod tests { assert_eq!(config.application, default_config.application); assert_eq!(config.keybindings, default_config.keybindings); assert_eq!(config.ui, default_config.ui); - assert_eq!(config.previewers, default_config.previewers); // backwards compatibility assert_eq!( config.shell_integration.commands, @@ -350,7 +342,7 @@ mod tests { theme = "television" [previewers.file] - theme = "Visual Studio Dark" + theme = "something" [keybindings] toggle_help = ["ctrl-a", "ctrl-b"] @@ -384,8 +376,6 @@ mod tests { default_config.application.frame_rate = 30.0; default_config.ui.ui_scale = 40; default_config.ui.theme = "television".to_string(); - default_config.previewers.file.theme = - "Visual Studio Dark".to_string(); default_config.keybindings.extend({ let mut map = FxHashMap::default(); map.insert( @@ -408,7 +398,6 @@ mod tests { assert_eq!(config.application, default_config.application); assert_eq!(config.keybindings, default_config.keybindings); assert_eq!(config.ui, default_config.ui); - assert_eq!(config.previewers, default_config.previewers); assert_eq!( config.shell_integration.commands, [(&String::from("git add"), &String::from("git-diff"))] diff --git a/television/config/previewers.rs b/television/config/previewers.rs deleted file mode 100644 index d891232..0000000 --- a/television/config/previewers.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::preview::{previewers, PreviewerConfig}; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Hash)] -pub struct PreviewersConfig { - #[serde(default)] - pub basic: BasicPreviewerConfig, - pub file: FilePreviewerConfig, - #[serde(default)] - pub env_var: EnvVarPreviewerConfig, -} - -impl From for PreviewerConfig { - fn from(val: PreviewersConfig) -> Self { - PreviewerConfig::default() - .file(previewers::files::FilePreviewerConfig::new(val.file.theme)) - } -} - -#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Hash)] -pub struct BasicPreviewerConfig {} - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Hash)] -#[serde(default)] -pub struct FilePreviewerConfig { - //pub max_file_size: u64, - pub theme: String, -} - -impl Default for FilePreviewerConfig { - fn default() -> Self { - Self { - //max_file_size: 1024 * 1024, - theme: String::from("TwoDark"), - } - } -} - -#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Hash)] -pub struct EnvVarPreviewerConfig {} diff --git a/television/event.rs b/television/event.rs index 8727feb..dd043dd 100644 --- a/television/event.rs +++ b/television/event.rs @@ -115,9 +115,7 @@ impl Display for Key { #[allow(clippy::module_name_repetitions)] pub struct EventLoop { pub rx: mpsc::UnboundedReceiver>, - //tx: mpsc::UnboundedSender>, pub abort_tx: mpsc::UnboundedSender<()>, - //tick_rate: std::time::Duration, } struct PollFuture { @@ -162,8 +160,7 @@ fn flush_existing_events() { } impl EventLoop { - // FIXME: this init parameter doesn't seem to be used anymore - pub fn new(tick_rate: f64, init: bool) -> Self { + pub fn new(tick_rate: f64) -> Self { let (tx, rx) = mpsc::unbounded_channel(); let tick_interval = Duration::from_secs_f64(1.0 / tick_rate); @@ -171,55 +168,52 @@ impl EventLoop { flush_existing_events(); - if init { - //let mut reader = crossterm::event::EventStream::new(); - tokio::spawn(async move { - loop { - let delay = tokio::time::sleep(tick_interval); - let event_available = poll_event(tick_interval); + tokio::spawn(async move { + loop { + let delay = tokio::time::sleep(tick_interval); + let event_available = poll_event(tick_interval); - tokio::select! { - // if we receive a message on the abort channel, stop the event loop - _ = abort_recv.recv() => { - tx.send(Event::Closed).unwrap_or_else(|_| warn!("Unable to send Closed event")); - tx.send(Event::Tick).unwrap_or_else(|_| warn!("Unable to send Tick event")); - break; - }, - _ = signal::ctrl_c() => { - debug!("Received SIGINT"); - tx.send(Event::Input(Key::Ctrl('c'))).unwrap_or_else(|_| warn!("Unable to send Ctrl-C event")); - }, - // if `delay` completes, pass to the next event "frame" - () = delay => { - tx.send(Event::Tick).unwrap_or_else(|_| warn!("Unable to send Tick event")); - }, - // if the receiver dropped the channel, stop the event loop - () = tx.closed() => break, - // if an event was received, process it - _ = event_available => { - let maybe_event = crossterm::event::read(); - match maybe_event { - Ok(crossterm::event::Event::Key(key)) => { - let key = convert_raw_event_to_key(key); - tx.send(Event::Input(key)).unwrap_or_else(|_| warn!("Unable to send {:?} event", key)); - }, - Ok(crossterm::event::Event::FocusLost) => { - tx.send(Event::FocusLost).unwrap_or_else(|_| warn!("Unable to send FocusLost event")); - }, - Ok(crossterm::event::Event::FocusGained) => { - tx.send(Event::FocusGained).unwrap_or_else(|_| warn!("Unable to send FocusGained event")); - }, - Ok(crossterm::event::Event::Resize(x, y)) => { - let (_, (new_x, new_y)) = flush_resize_events((x, y)); - tx.send(Event::Resize(new_x, new_y)).unwrap_or_else(|_| warn!("Unable to send Resize event")); - }, - _ => {} - } + tokio::select! { + // if we receive a message on the abort channel, stop the event loop + _ = abort_recv.recv() => { + tx.send(Event::Closed).unwrap_or_else(|_| warn!("Unable to send Closed event")); + tx.send(Event::Tick).unwrap_or_else(|_| warn!("Unable to send Tick event")); + break; + }, + _ = signal::ctrl_c() => { + debug!("Received SIGINT"); + tx.send(Event::Input(Key::Ctrl('c'))).unwrap_or_else(|_| warn!("Unable to send Ctrl-C event")); + }, + // if `delay` completes, pass to the next event "frame" + () = delay => { + tx.send(Event::Tick).unwrap_or_else(|_| warn!("Unable to send Tick event")); + }, + // if the receiver dropped the channel, stop the event loop + () = tx.closed() => break, + // if an event was received, process it + _ = event_available => { + let maybe_event = crossterm::event::read(); + match maybe_event { + Ok(crossterm::event::Event::Key(key)) => { + let key = convert_raw_event_to_key(key); + tx.send(Event::Input(key)).unwrap_or_else(|_| warn!("Unable to send {:?} event", key)); + }, + Ok(crossterm::event::Event::FocusLost) => { + tx.send(Event::FocusLost).unwrap_or_else(|_| warn!("Unable to send FocusLost event")); + }, + Ok(crossterm::event::Event::FocusGained) => { + tx.send(Event::FocusGained).unwrap_or_else(|_| warn!("Unable to send FocusGained event")); + }, + Ok(crossterm::event::Event::Resize(x, y)) => { + let (_, (new_x, new_y)) = flush_resize_events((x, y)); + tx.send(Event::Resize(new_x, new_y)).unwrap_or_else(|_| warn!("Unable to send Resize event")); + }, + _ => {} } } } - }); - } + } + }); Self { //tx, diff --git a/television/main.rs b/television/main.rs index a8d09cd..3809814 100644 --- a/television/main.rs +++ b/television/main.rs @@ -5,16 +5,14 @@ use std::process::exit; use anyhow::Result; use clap::Parser; -use crossterm::terminal::enable_raw_mode; use television::cable; -use television::channels::cable::prototypes::CableChannels; +use television::channels::cable::prototypes::{ + CableChannelPrototype, CableChannelPrototypes, +}; use television::utils::clipboard::CLIPBOARD; use tracing::{debug, error, info}; use television::app::{App, AppOptions}; -use television::channels::{ - stdin::Channel as StdinChannel, TelevisionChannel, -}; use television::cli::{ args::{Cli, Command}, guess_channel_from_prompt, list_channels, PostProcessedCli, @@ -53,8 +51,6 @@ async fn main() -> Result<()> { .as_ref() .map(|x| handle_subcommands(x, &config)); - enable_raw_mode()?; - // optionally change the working directory args.working_directory.as_ref().map(set_current_dir); @@ -81,7 +77,8 @@ async fn main() -> Result<()> { args.no_help, config.application.tick_rate, ); - let mut app = App::new(channel, config, args.input, options); + let mut app = + App::new(channel, config, args.input, options, &cable_channels); stdout().flush()?; debug!("Running application..."); let output = app.run(stdout().is_terminal(), false).await?; @@ -157,26 +154,24 @@ pub fn determine_channel( args: PostProcessedCli, config: &Config, readable_stdin: bool, - cable_channels: &CableChannels, -) -> Result { + cable_channels: &CableChannelPrototypes, +) -> Result { if readable_stdin { debug!("Using stdin channel"); - Ok(TelevisionChannel::Stdin(StdinChannel::new( - args.preview_kind, - ))) + Ok(CableChannelPrototype::stdin(args.preview_command)) } else if let Some(prompt) = args.autocomplete_prompt { debug!("Using autocomplete prompt: {:?}", prompt); - let channel = guess_channel_from_prompt( + let channel_prototype = guess_channel_from_prompt( &prompt, &config.shell_integration.commands, &config.shell_integration.fallback_channel, cable_channels, )?; - debug!("Using guessed channel: {:?}", channel); - Ok(TelevisionChannel::Cable(channel.into())) + debug!("Using guessed channel: {:?}", channel_prototype); + Ok(channel_prototype) } else { debug!("Using {:?} channel", args.channel); - Ok(TelevisionChannel::Cable(args.channel.into())) + Ok(args.channel) } } @@ -185,9 +180,7 @@ mod tests { use rustc_hash::FxHashMap; use television::{ cable::load_cable_channels, - channels::{ - cable::prototypes::CableChannelPrototype, preview::PreviewType, - }, + channels::cable::prototypes::CableChannelPrototype, }; use super::*; @@ -196,21 +189,19 @@ mod tests { args: &PostProcessedCli, config: &Config, readable_stdin: bool, - expected_channel: &TelevisionChannel, - cable_channels: Option, + expected_channel: &CableChannelPrototype, + cable_channels: Option, ) { - let channels: CableChannels = cable_channels + let channels: CableChannelPrototypes = cable_channels .unwrap_or_else(|| load_cable_channels().unwrap_or_default()); let channel = determine_channel(args.clone(), config, readable_stdin, &channels) .unwrap(); assert_eq!( - channel.name(), - expected_channel.name(), + channel.name, expected_channel.name, "Expected {:?} but got {:?}", - expected_channel.name(), - channel.name() + expected_channel.name, channel.name ); } @@ -227,7 +218,9 @@ mod tests { &args, &config, true, - &TelevisionChannel::Stdin(StdinChannel::new(PreviewType::None)), + &CableChannelPrototype::new( + "stdin", "cat", false, None, None, None, + ), None, ); } @@ -235,11 +228,8 @@ mod tests { #[tokio::test] async fn test_determine_channel_autocomplete_prompt() { let autocomplete_prompt = Some("cd".to_string()); - let expected_channel = TelevisionChannel::Cable( - CableChannelPrototype::new( - "dirs", "ls {}", false, None, None, None, - ) - .into(), + let expected_channel = CableChannelPrototype::new( + "dirs", "ls {}", false, None, None, None, ); let args = PostProcessedCli { autocomplete_prompt, @@ -283,12 +273,7 @@ mod tests { &args, &config, false, - &TelevisionChannel::Cable( - CableChannelPrototype::new( - "dirs", "", false, None, None, None, - ) - .into(), - ), + &CableChannelPrototype::new("dirs", "", false, None, None, None), None, ); } diff --git a/television/preview/ansi.rs b/television/preview/ansi.rs deleted file mode 100644 index f841281..0000000 --- a/television/preview/ansi.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![allow(unused_imports)] -//! This module provides a way to parse ansi escape codes and convert them to ratatui objects. -//! -//! This code is a modified version of [ansi_to_tui](https://github.com/ratatui/ansi-to-tui). - -// mod ansi; -pub mod code; -pub mod error; -pub mod parser; -pub use error::Error; -use ratatui::text::Text; - -/// `IntoText` will convert any type that has a `AsRef<[u8]>` to a Text. -pub trait IntoText { - /// Convert the type to a Text. - #[allow(clippy::wrong_self_convention)] - fn into_text(&self) -> Result, Error>; - /// Convert the type to a Text while trying to copy as less as possible - #[cfg(feature = "zero-copy")] - fn to_text(&self) -> Result, Error>; -} -impl IntoText for T -where - T: AsRef<[u8]>, -{ - fn into_text(&self) -> Result, Error> { - Ok(parser::text(self.as_ref())?.1) - } - - #[cfg(feature = "zero-copy")] - fn to_text(&self) -> Result, Error> { - Ok(parser::text_fast(self.as_ref())?.1) - } -} diff --git a/television/preview/ansi/LICENSE b/television/preview/ansi/LICENSE deleted file mode 100644 index 73313cb..0000000 --- a/television/preview/ansi/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -Copyright 2021 Uttarayan Mondal - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/television/preview/ansi/code.rs b/television/preview/ansi/code.rs deleted file mode 100644 index d23d3c9..0000000 --- a/television/preview/ansi/code.rs +++ /dev/null @@ -1,140 +0,0 @@ -use ratatui::style::Color; - -/// This enum stores most types of ansi escape sequences -/// -/// You can turn an escape sequence to this enum variant using -/// `AnsiCode::from(code: u8)` -/// This doesn't support all of them but does support most of them. - -#[derive(Debug, PartialEq, Clone)] -#[non_exhaustive] -pub enum AnsiCode { - /// Reset the terminal - Reset, - /// Set font to bold - Bold, - /// Set font to faint - Faint, - /// Set font to italic - Italic, - /// Set font to underline - Underline, - /// Set cursor to slowblink - SlowBlink, - /// Set cursor to rapidblink - RapidBlink, - /// Invert the colors - Reverse, - /// Conceal text - Conceal, - /// Display crossed out text - CrossedOut, - /// Choose primary font - PrimaryFont, - /// Choose alternate font - AlternateFont, - /// Choose alternate fonts 1-9 - #[allow(dead_code)] - AlternateFonts(u8), // = 11..19, // from 11 to 19 - /// Fraktur ? No clue - Fraktur, - /// Turn off bold - BoldOff, - /// Set text to normal - Normal, - /// Turn off Italic - NotItalic, - /// Turn off underline - UnderlineOff, - /// Turn off blinking - BlinkOff, - // 26 ? - /// Don't invert colors - InvertOff, - /// Reveal text - Reveal, - /// Turn off Crossedout text - CrossedOutOff, - /// Set foreground color (4-bit) - ForegroundColor(Color), //, 31..37//Issue 60553 https://github.com/rust-lang/rust/issues/60553 - /// Set foreground color (8-bit and 24-bit) - SetForegroundColor, - /// Default foreground color - DefaultForegroundColor, - /// Set background color (4-bit) - BackgroundColor(Color), // 41..47 - /// Set background color (8-bit and 24-bit) - SetBackgroundColor, - /// Default background color - DefaultBackgroundColor, // 49 - /// Other / non supported escape codes - Code(Vec), -} - -impl From for AnsiCode { - fn from(code: u8) -> Self { - match code { - 0 => AnsiCode::Reset, - 1 => AnsiCode::Bold, - 2 => AnsiCode::Faint, - 3 => AnsiCode::Italic, - 4 => AnsiCode::Underline, - 5 => AnsiCode::SlowBlink, - 6 => AnsiCode::RapidBlink, - 7 => AnsiCode::Reverse, - 8 => AnsiCode::Conceal, - 9 => AnsiCode::CrossedOut, - 10 => AnsiCode::PrimaryFont, - 11 => AnsiCode::AlternateFont, - // AnsiCode::// AlternateFont = 11..19, // from 11 to 19 - 20 => AnsiCode::Fraktur, - 21 => AnsiCode::BoldOff, - 22 => AnsiCode::Normal, - 23 => AnsiCode::NotItalic, - 24 => AnsiCode::UnderlineOff, - 25 => AnsiCode::BlinkOff, - // 26 ? - 27 => AnsiCode::InvertOff, - 28 => AnsiCode::Reveal, - 29 => AnsiCode::CrossedOutOff, - 30 => AnsiCode::ForegroundColor(Color::Black), - 31 => AnsiCode::ForegroundColor(Color::Red), - 32 => AnsiCode::ForegroundColor(Color::Green), - 33 => AnsiCode::ForegroundColor(Color::Yellow), - 34 => AnsiCode::ForegroundColor(Color::Blue), - 35 => AnsiCode::ForegroundColor(Color::Magenta), - 36 => AnsiCode::ForegroundColor(Color::Cyan), - 37 => AnsiCode::ForegroundColor(Color::Gray), - 38 => AnsiCode::SetForegroundColor, - 39 => AnsiCode::DefaultForegroundColor, - 40 => AnsiCode::BackgroundColor(Color::Black), - 41 => AnsiCode::BackgroundColor(Color::Red), - 42 => AnsiCode::BackgroundColor(Color::Green), - 43 => AnsiCode::BackgroundColor(Color::Yellow), - 44 => AnsiCode::BackgroundColor(Color::Blue), - 45 => AnsiCode::BackgroundColor(Color::Magenta), - 46 => AnsiCode::BackgroundColor(Color::Cyan), - 47 => AnsiCode::BackgroundColor(Color::Gray), - 48 => AnsiCode::SetBackgroundColor, - 49 => AnsiCode::DefaultBackgroundColor, - 90 => AnsiCode::ForegroundColor(Color::DarkGray), - 91 => AnsiCode::ForegroundColor(Color::LightRed), - 92 => AnsiCode::ForegroundColor(Color::LightGreen), - 93 => AnsiCode::ForegroundColor(Color::LightYellow), - 94 => AnsiCode::ForegroundColor(Color::LightBlue), - 95 => AnsiCode::ForegroundColor(Color::LightMagenta), - 96 => AnsiCode::ForegroundColor(Color::LightCyan), - #[allow(clippy::match_same_arms)] - 97 => AnsiCode::ForegroundColor(Color::White), - 100 => AnsiCode::BackgroundColor(Color::DarkGray), - 101 => AnsiCode::BackgroundColor(Color::LightRed), - 102 => AnsiCode::BackgroundColor(Color::LightGreen), - 103 => AnsiCode::BackgroundColor(Color::LightYellow), - 104 => AnsiCode::BackgroundColor(Color::LightBlue), - 105 => AnsiCode::BackgroundColor(Color::LightMagenta), - 106 => AnsiCode::BackgroundColor(Color::LightCyan), - 107 => AnsiCode::ForegroundColor(Color::White), - code => AnsiCode::Code(vec![code]), - } - } -} diff --git a/television/preview/ansi/error.rs b/television/preview/ansi/error.rs deleted file mode 100644 index 4930749..0000000 --- a/television/preview/ansi/error.rs +++ /dev/null @@ -1,24 +0,0 @@ -/// This enum stores the error types -#[derive(Debug, thiserror::Error, PartialEq)] -pub enum Error { - /// Stack is empty (should never happen) - #[error("Internal error: stack is empty")] - NomError(String), - - /// Error parsing the input as utf-8 - #[cfg(feature = "simd")] - /// Cannot determine the foreground or background - #[error("{0:?}")] - Utf8Error(#[from] simdutf8::basic::Utf8Error), - - #[cfg(not(feature = "simd"))] - /// Cannot determine the foreground or background - #[error("{0:?}")] - Utf8Error(#[from] std::string::FromUtf8Error), -} - -impl From>> for Error { - fn from(e: nom::Err>) -> Self { - Self::NomError(format!("{:?}", e)) - } -} diff --git a/television/preview/ansi/parser.rs b/television/preview/ansi/parser.rs deleted file mode 100644 index a24cb86..0000000 --- a/television/preview/ansi/parser.rs +++ /dev/null @@ -1,461 +0,0 @@ -use crate::preview::ansi::code::AnsiCode; -use nom::{ - branch::alt, - bytes::complete::{tag, take, take_till, take_while}, - character::{ - complete::{char, i64, not_line_ending, u8}, - is_alphabetic, - }, - combinator::{map_res, opt}, - multi::fold_many0, - sequence::{delimited, preceded, tuple}, - IResult, Parser, -}; -use ratatui::{ - style::{Color, Modifier, Style, Stylize}, - text::{Line, Span, Text}, -}; -use smallvec::SmallVec; -use std::str::FromStr; - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -enum ColorType { - /// Eight Bit color - EightBit, - /// 24-bit color or true color - TrueColor, -} - -#[derive(Debug, Clone, PartialEq)] -struct AnsiItem { - code: AnsiCode, - color: Option, -} - -#[derive(Debug, Clone, PartialEq)] -struct AnsiStates { - pub items: SmallVec<[AnsiItem; 2]>, - pub style: Style, -} - -impl From for Style { - fn from(states: AnsiStates) -> Self { - let mut style = states.style; - for item in states.items { - match item.code { - AnsiCode::Bold => style = style.add_modifier(Modifier::BOLD), - AnsiCode::Faint => style = style.add_modifier(Modifier::DIM), - AnsiCode::Normal => { - style = style - .remove_modifier(Modifier::BOLD) - .remove_modifier(Modifier::DIM); - } - AnsiCode::Italic => { - style = style.add_modifier(Modifier::ITALIC); - } - AnsiCode::Underline => { - style = style.add_modifier(Modifier::UNDERLINED); - } - AnsiCode::SlowBlink => { - style = style.add_modifier(Modifier::SLOW_BLINK); - } - AnsiCode::RapidBlink => { - style = style.add_modifier(Modifier::RAPID_BLINK); - } - AnsiCode::Reverse => { - style = style.add_modifier(Modifier::REVERSED); - } - AnsiCode::Conceal => { - style = style.add_modifier(Modifier::HIDDEN); - } - AnsiCode::CrossedOut => { - style = style.add_modifier(Modifier::CROSSED_OUT); - } - AnsiCode::DefaultForegroundColor => { - style = style.fg(Color::Reset); - } - AnsiCode::SetForegroundColor => { - if let Some(color) = item.color { - style = style.fg(color); - } - } - AnsiCode::ForegroundColor(color) => style = style.fg(color), - AnsiCode::Reset => style = style.fg(Color::Reset), - _ => (), - } - } - style - } -} - -#[allow(clippy::unnecessary_wraps)] -pub(crate) fn text(mut s: &[u8]) -> IResult<&[u8], Text<'static>> { - let mut lines = Vec::new(); - let mut last_style = Style::new(); - while let Ok((remaining, (line, style))) = line(last_style)(s) { - lines.push(line); - last_style = style; - s = remaining; - if s.is_empty() { - break; - } - } - Ok((s, Text::from(lines))) -} - -#[cfg(feature = "zero-copy")] -#[allow(clippy::unnecessary_wraps)] -pub(crate) fn text_fast(mut s: &[u8]) -> IResult<&[u8], Text<'_>> { - let mut lines = Vec::new(); - let mut last = Style::new(); - while let Ok((c, (line, style))) = line_fast(last)(s) { - lines.push(line); - last = style; - s = c; - if s.is_empty() { - break; - } - } - Ok((s, Text::from(lines))) -} - -fn line( - style: Style, -) -> impl Fn(&[u8]) -> IResult<&[u8], (Line<'static>, Style)> { - // let style_: Style = Default::default(); - move |s: &[u8]| -> IResult<&[u8], (Line<'static>, Style)> { - // consume s until a line ending is found - let (s, mut text) = not_line_ending(s)?; - // discard the line ending - let (s, _) = opt(alt((tag("\r\n"), tag("\n"))))(s)?; - let mut spans = Vec::new(); - // carry over the style from the previous line (passed in as an argument) - let mut last_style = style; - // parse spans from the given text - while let Ok((remaining, span)) = span(last_style)(text) { - // Since reset now tracks separately we can skip the reset check - last_style = last_style.patch(span.style); - - if !span.content.is_empty() { - spans.push(span); - } - text = remaining; - if text.is_empty() { - break; - } - } - - // NOTE: what is last_style here - Ok((s, (Line::from(spans), last_style))) - } -} - -#[cfg(feature = "zero-copy")] -fn line_fast( - style: Style, -) -> impl Fn(&[u8]) -> IResult<&[u8], (Line<'_>, Style)> { - // let style_: Style = Default::default(); - move |s: &[u8]| -> IResult<&[u8], (Line<'_>, Style)> { - let (s, mut text) = not_line_ending(s)?; - let (s, _) = opt(alt((tag("\r\n"), tag("\n"))))(s)?; - let mut spans = Vec::new(); - let mut last = style; - while let Ok((s, span)) = span_fast(last)(text) { - last = last.patch(span.style); - // If the spans is empty then it might be possible that the style changes - // but there is no text change - if !span.content.is_empty() { - spans.push(span); - } - text = s; - if text.is_empty() { - break; - } - } - - Ok((s, (Line::from(spans), last))) - } -} - -// fn span(s: &[u8]) -> IResult<&[u8], tui::text::Span> { -fn span( - last: Style, -) -> impl Fn(&[u8]) -> IResult<&[u8], Span<'static>, nom::error::Error<&[u8]>> -{ - move |s: &[u8]| -> IResult<&[u8], Span<'static>> { - let mut last_style = last; - // optionally consume a style - let (s, maybe_style) = opt(style(last_style))(s)?; - - // consume until an escape sequence is found - #[cfg(feature = "simd")] - let (s, text) = map_res(take_while(|c| c != b'\x1b'), |t| { - simdutf8::basic::from_utf8(t) - })(s)?; - - #[cfg(not(feature = "simd"))] - let (s, text) = - map_res(take_while(|c| c != b'\x1b'), |t| std::str::from_utf8(t))( - s, - )?; - - // if a style was found, patch the last style with it - if let Some(st) = maybe_style.flatten() { - last_style = last_style.patch(st); - } - - Ok((s, Span::styled(text.to_owned(), last_style))) - } -} - -#[cfg(feature = "zero-copy")] -fn span_fast( - last: Style, -) -> impl Fn(&[u8]) -> IResult<&[u8], Span<'_>, nom::error::Error<&[u8]>> { - move |s: &[u8]| -> IResult<&[u8], Span<'_>> { - let mut last = last; - let (s, style) = opt(style(last))(s)?; - - #[cfg(feature = "simd")] - let (s, text) = map_res(take_while(|c| c != b'\x1b'), |t| { - simdutf8::basic::from_utf8(t) - })(s)?; - - #[cfg(not(feature = "simd"))] - let (s, text) = - map_res(take_while(|c| c != b'\x1b'), |t| std::str::from_utf8(t))( - s, - )?; - - if let Some(style) = style.flatten() { - last = last.patch(style); - } - - Ok((s, Span::styled(text, last))) - } -} - -#[allow(clippy::type_complexity)] -fn style( - style: Style, -) -> impl Fn(&[u8]) -> IResult<&[u8], Option