diff --git a/.config/config.json5 b/.config/config.json5 index c746239..898b2de 100644 --- a/.config/config.json5 +++ b/.config/config.json5 @@ -2,8 +2,7 @@ "keybindings": { "Home": { "": "Quit", // Quit the application - "": "Quit", // Another way to quit - "": "Quit", // Yet another way to quit + "": "Quit", // Another way to quit "": "Suspend" // Suspend the application }, } diff --git a/Cargo.lock b/Cargo.lock index 497574b..b240076 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.88" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356" +checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95" [[package]] name = "arc-swap" @@ -128,20 +128,20 @@ checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" @@ -205,7 +205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", - "regex-automata 0.4.7", + "regex-automata 0.4.8", "serde", ] @@ -223,9 +223,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "camino" @@ -276,9 +276,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.18" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ "shlex", ] @@ -306,9 +306,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.17" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -316,9 +316,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.17" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -326,19 +326,19 @@ dependencies = [ "strsim", "terminal_size", "unicase", - "unicode-width", + "unicode-width 0.2.0", ] [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -550,7 +550,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -561,7 +561,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -575,33 +575,33 @@ dependencies = [ [[package]] name = "derive_builder" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "derive_builder_macro" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -696,7 +696,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -751,9 +751,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide 0.8.0", @@ -765,6 +765,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -776,9 +782,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -791,9 +797,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -801,15 +807,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -818,38 +824,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -884,18 +890,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "getset" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f636605b743120a8d32ed92fc27b6cde1a769f8f936c065151eb66f88ded513c" -dependencies = [ - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.77", -] - [[package]] name = "gimli" version = "0.28.1" @@ -904,9 +898,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "gix" -version = "0.63.0" +version = "0.66.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "984c5018adfa7a4536ade67990b3ebc6e11ab57b3d6cd9968de0947ca99b4b06" +checksum = "9048b8d1ae2104f045cb37e5c450fc49d5d8af22609386bfc739c11ba88995eb" dependencies = [ "gix-actor", "gix-commitgraph", @@ -921,7 +915,6 @@ dependencies = [ "gix-hashtable", "gix-index", "gix-lock", - "gix-macros", "gix-object", "gix-odb", "gix-pack", @@ -946,9 +939,9 @@ dependencies = [ [[package]] name = "gix-actor" -version = "0.31.5" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e454357e34b833cc3a00b6efbbd3dd4d18b24b9fb0c023876ec2645e8aa3f2" +checksum = "fc19e312cd45c4a66cd003f909163dc2f8e1623e30a0c0c6df3776e89b308665" dependencies = [ "bstr", "gix-date", @@ -992,9 +985,9 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fafe42957e11d98e354a66b6bd70aeea00faf2f62dd11164188224a507c840" +checksum = "78e797487e6ca3552491de1131b4f72202f282fb33f198b1c34406d765b42bb0" dependencies = [ "bstr", "gix-config-value", @@ -1026,21 +1019,21 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.8.7" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eed6931f21491ee0aeb922751bd7ec97b4b2fe8fbfedcb678e2a2dce5f3b8c0" +checksum = "35c84b7af01e68daf7a6bb8bb909c1ff5edb3ce4326f1f43063a5a96d3c3c8a5" dependencies = [ "bstr", "itoa", + "jiff", "thiserror", - "time", ] [[package]] name = "gix-diff" -version = "0.44.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1996d5c8a305b59709467d80617c9fde48d9d75fd1f4179ea970912630886c9d" +checksum = "92c9afd80fff00f8b38b1c1928442feb4cd6d2232a6ed806b6b193151a3d336c" dependencies = [ "bstr", "gix-hash", @@ -1050,9 +1043,9 @@ dependencies = [ [[package]] name = "gix-discover" -version = "0.32.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc27c699b63da66b50d50c00668bc0b7e90c3a382ef302865e891559935f3dbf" +checksum = "0577366b9567376bc26e815fd74451ebd0e6218814e242f8e5b7072c58d956d2" dependencies = [ "bstr", "dunce", @@ -1129,9 +1122,9 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.33.1" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9a44eb55bd84bb48f8a44980e951968ced21e171b22d115d1cdcef82a7d73f" +checksum = "0cd4203244444017682176e65fd0180be9298e58ed90bd4a8489a357795ed22d" dependencies = [ "bitflags", "bstr", @@ -1166,22 +1159,11 @@ dependencies = [ "thiserror", ] -[[package]] -name = "gix-macros" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999ce923619f88194171a67fb3e6d613653b8d4d6078b529b15a765da0edcc17" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - [[package]] name = "gix-object" -version = "0.42.3" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25da2f46b4e7c2fa7b413ce4dffb87f69eaf89c2057e386491f4c55cadbfe386" +checksum = "2f5b801834f1de7640731820c2df6ba88d95480dc4ab166a5882f8ff12b88efa" dependencies = [ "bstr", "gix-actor", @@ -1198,9 +1180,9 @@ dependencies = [ [[package]] name = "gix-odb" -version = "0.61.1" +version = "0.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20d384fe541d93d8a3bb7d5d5ef210780d6df4f50c4e684ccba32665a5e3bc9b" +checksum = "a3158068701c17df54f0ab2adda527f5a6aca38fd5fd80ceb7e3c0a2717ec747" dependencies = [ "arc-swap", "gix-date", @@ -1218,9 +1200,9 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.51.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0594491fffe55df94ba1c111a6566b7f56b3f8d2e1efc750e77d572f5f5229" +checksum = "3223aa342eee21e1e0e403cad8ae9caf9edca55ef84c347738d10681676fd954" dependencies = [ "clru", "gix-chunk", @@ -1260,12 +1242,11 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.44.1" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3394a2997e5bc6b22ebc1e1a87b41eeefbcfcff3dbfa7c4bd73cb0ac8f1f3e2e" +checksum = "ae0d8406ebf9aaa91f55a57f053c5a1ad1a39f60fdf0303142b7be7ea44311e5" dependencies = [ "gix-actor", - "gix-date", "gix-features", "gix-fs", "gix-hash", @@ -1282,9 +1263,9 @@ dependencies = [ [[package]] name = "gix-refspec" -version = "0.23.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6868f8cd2e62555d1f7c78b784bece43ace40dd2a462daf3b588d5416e603f37" +checksum = "ebb005f82341ba67615ffdd9f7742c87787544441c88090878393d0682869ca6" dependencies = [ "bstr", "gix-hash", @@ -1296,9 +1277,9 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.27.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b13e43c2118c4b0537ddac7d0821ae0dfa90b7b8dbf20c711e153fb749adce" +checksum = "ba4621b219ac0cdb9256883030c3d56a6c64a6deaa829a92da73b9a576825e1e" dependencies = [ "bstr", "gix-date", @@ -1312,9 +1293,9 @@ dependencies = [ [[package]] name = "gix-revwalk" -version = "0.13.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b030ccaab71af141f537e0225f19b9e74f25fefdba0372246b844491cab43e0" +checksum = "b41e72544b93084ee682ef3d5b31b1ba4d8fa27a017482900e5e044d5b1b3984" dependencies = [ "gix-commitgraph", "gix-date", @@ -1360,9 +1341,9 @@ checksum = "6cae0e8661c3ff92688ce1c8b8058b3efb312aba9492bbe93661a21705ab431b" [[package]] name = "gix-traverse" -version = "0.39.2" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e499a18c511e71cf4a20413b743b9f5bcf64b3d9e81e9c3c6cd399eae55a8840" +checksum = "030da39af94e4df35472e9318228f36530989327906f38e27807df305fccb780" dependencies = [ "bitflags", "gix-commitgraph", @@ -1401,9 +1382,9 @@ dependencies = [ [[package]] name = "gix-validate" -version = "0.8.5" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c27dd34a49b1addf193c92070bcbf3beaf6e10f16a78544de6372e146a0acf" +checksum = "81f2badbb64e57b404593ee26b752c26991910fd0d81fe6f9a71c1a8309b6c86" dependencies = [ "bstr", "thiserror", @@ -1425,6 +1406,17 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "heck" version = "0.5.0" @@ -1482,15 +1474,15 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "human-panic" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c5a08ed290eac04006e21e63d32e90086b6182c7cd0452d10f4264def1fec9a" +checksum = "80b84a66a325082740043a6c28bbea400c129eac0d3a27673a1de971e44bf1f7" dependencies = [ "anstream", "anstyle", @@ -1504,9 +1496,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -1541,9 +1533,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-channel", @@ -1554,16 +1546,15 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1606,12 +1597,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -1621,14 +1612,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "ipnet" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_terminal_polyfill" @@ -1651,11 +1642,36 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jiff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a45489186a6123c128fdf6016183fcfab7113e1820eb813127e036e287233fb" +dependencies = [ + "jiff-tzdb-platform", + "windows-sys 0.59.0", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91335e575850c5c4c673b9bd467b0e025f164ca59d0564f69d0c2ee0ffad4653" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9835f0060a626fe59f160437bc725491a6af23133ea906500027d1bd2f8f4329" +dependencies = [ + "jiff-tzdb", +] + [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -1679,9 +1695,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libredox" @@ -1724,11 +1740,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -1748,9 +1764,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] @@ -1853,9 +1869,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "option-ext" @@ -1927,9 +1943,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" [[package]] name = "percent-encoding" @@ -1939,9 +1955,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.12" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c73c26c01b8c87956cea613c907c9d6ecffd8d18a2a5908e5de0adfaa185cea" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -1950,9 +1966,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.12" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664d22978e2815783adbdd2c588b455b1bd625299ce36b2a99881ac9627e6d8d" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" dependencies = [ "pest", "pest_generator", @@ -1960,48 +1976,28 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.12" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d5487022d5d33f4c30d91c22afa240ce2a644e87fe08caad974d4eab6badbe" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "pest_meta" -version = "2.7.12" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0091754bbd0ea592c4deb3a122ce8ecbb0753b738aa82bc055fcc2eccc8d8174" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" dependencies = [ "once_cell", "pest", "sha2", ] -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -2031,41 +2027,19 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", ] -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.77", -] - [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -2182,14 +2156,14 @@ dependencies = [ "strum_macros", "unicode-segmentation", "unicode-truncate", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] name = "redox_syscall" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags", ] @@ -2207,14 +2181,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -2228,13 +2202,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -2245,15 +2219,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.7" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", @@ -2355,9 +2329,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.13" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "once_cell", "ring", @@ -2369,19 +2343,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -2396,9 +2369,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -2447,14 +2420,14 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -2470,14 +2443,14 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -2613,7 +2586,8 @@ dependencies = [ "tracing-error", "tracing-subscriber", "transmission-rpc", - "unicode-width", + "tui-tree-widget", + "unicode-width 0.1.14", "vergen-gix", ] @@ -2663,7 +2637,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -2685,9 +2659,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", @@ -2705,9 +2679,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -2718,32 +2692,32 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" dependencies = [ "rustix", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -2839,7 +2813,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -2889,9 +2863,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", @@ -2900,27 +2874,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - [[package]] name = "tower-service" version = "0.3.3" @@ -2946,7 +2899,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -3019,6 +2972,16 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tui-tree-widget" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0b54061d997162f225bed5d2147574af0648480214759a000e33f6cea0017a" +dependencies = [ + "ratatui", + "unicode-width 0.1.14", +] + [[package]] name = "typenum" version = "1.17.0" @@ -3027,24 +2990,21 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-bom" @@ -3060,18 +3020,18 @@ checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-truncate" @@ -3081,14 +3041,20 @@ checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ "itertools", "unicode-segmentation", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "untrusted" @@ -3115,9 +3081,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", ] @@ -3130,14 +3096,13 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "vergen" -version = "9.0.0" +version = "9.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c32e7318e93a9ac53693b6caccfb05ff22e04a44c7cf8a279051f24c09da286f" +checksum = "349ed9e45296a581f455bc18039878f409992999bc1d5da12a6800eb18c8752f" dependencies = [ "anyhow", "cargo_metadata", "derive_builder", - "getset", "regex", "rustversion", "time", @@ -3146,9 +3111,9 @@ dependencies = [ [[package]] name = "vergen-gix" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e353ce10596ac5821aaf76e4952360f6d08d3ece9498564d066167bb0f437c94" +checksum = "02ef5d49e57c96e025770171c1c7ee0e30cd6f712f21a1fe501a58be6d069192" dependencies = [ "anyhow", "derive_builder", @@ -3161,13 +3126,12 @@ dependencies = [ [[package]] name = "vergen-lib" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06bee42361e43b60f363bad49d63798d0f42fb1768091812270eca00c784720" +checksum = "229eaddb0050920816cf051e619affaf18caa3dd512de8de5839ccbc8e53abb0" dependencies = [ "anyhow", "derive_builder", - "getset", "rustversion", ] @@ -3224,9 +3188,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -3235,24 +3199,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -3262,9 +3226,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3272,28 +3236,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -3301,9 +3265,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.5" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -3528,9 +3492,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -3546,9 +3510,9 @@ dependencies = [ [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "zerocopy" @@ -3568,7 +3532,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 76e0e77..a4aacb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ tracing = "0.1.40" tracing-error = "0.2.0" tracing-subscriber = { version = "0.3.18", features = ["env-filter", "serde"] } transmission-rpc = "0.4.3" +tui-tree-widget = "0.22.0" unicode-width = "0.1.13" [build-dependencies] diff --git a/README.md b/README.md index 14afe95..4732637 100644 --- a/README.md +++ b/README.md @@ -80,18 +80,18 @@ sparrow --username "user" --password "very_secret_password" - Info -| Key | Description | -| :---- | :--------------------- | -| `l` | Next tab | -| `h` | Previous tab | -| `Esc` | Go back | -| `q` | Quit | -| `Q` | Quit and close session | +| Key | Description | +| :----------------- | :--------------------- | +| `l` | Next tab | +| `h` | Previous tab | +| `Esc`, `Backspace` | Go back | +| `q` | Quit | +| `Q` | Quit and close session | ## TODO - [x] Add a component to show torrent information -- [x] Better error handling +- [ ] Better error handling - [ ] Filter/Search for torrents in the list - [ ] Add a help modal/page to show keybindings - [ ] File viewer for the torrents diff --git a/src/app.rs b/src/app.rs index 3c2617f..ca0ea33 100644 --- a/src/app.rs +++ b/src/app.rs @@ -16,23 +16,23 @@ use crate::{ }; #[derive(Clone, Debug)] -pub enum AppError { +pub enum Error { OutOfBound, NoRowSelected, WithMessage(String), } -impl std::fmt::Display for AppError { +impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - AppError::OutOfBound => write!(f, "Index out of bound"), - AppError::NoRowSelected => write!(f, "No row selected!"), - AppError::WithMessage(msg) => write!(f, "Message: {}", msg), + Error::OutOfBound => write!(f, "Index out of bound"), + Error::NoRowSelected => write!(f, "No row selected!"), + Error::WithMessage(msg) => write!(f, "Message: {msg}"), } } } -impl std::error::Error for AppError {} +impl std::error::Error for Error {} pub struct App { config: Config, @@ -192,14 +192,13 @@ impl App { } fn handle_modes(&mut self, mode: Mode, id: i64) -> Result<()> { + self.components.pop(); match mode { Mode::Home => { - self.components.pop(); self.components .push(Box::new(Home::new(self.client.clone(), Some(id))?)); } Mode::Properties => { - self.components.pop(); self.components .push(Box::new(Properties::new(self.client.clone(), id)?)); } diff --git a/src/components/home.rs b/src/components/home.rs index 3774e01..0d6c511 100644 --- a/src/components/home.rs +++ b/src/components/home.rs @@ -21,10 +21,10 @@ use unicode_width::UnicodeWidthStr; use super::Component; use crate::{ action::Action, - app::{AppError, Mode}, + app::{self, Mode}, colors::Colors, config::Config, - data::{map_torrent_data, TorrentData}, + data::{self, map_torrent_data}, }; const ITEM_HEIGHT: usize = 4; @@ -33,7 +33,7 @@ const SCROLL_SIZE: usize = 4; pub struct Home { client: Rc>, state: TableState, - items: Vec, + items: Vec, longest_item_lens: (u16, u16, u16, u16, u16, u16), colors: Colors, scroll_state: ScrollbarState, @@ -45,11 +45,12 @@ impl Home { pub fn new(client: Rc>, id: Option) -> Result { let data_vec = block_on(map_torrent_data(&client, None))?; let index = match id { - Some(id) => data_vec - .iter() - .enumerate() - .filter_map(|(i, d)| if d.id == id { Some(i) } else { None }) - .next(), + Some(id) => { + data_vec + .iter() + .enumerate() + .find_map(|(i, d)| if d.id == id { Some(i) } else { None }) + } None => Some(0), }; @@ -68,13 +69,13 @@ impl Home { async fn toggle_state(&mut self) -> types::Result<()> { let id = self .items - .get(self.state.selected().ok_or(AppError::NoRowSelected)?) - .ok_or(AppError::OutOfBound)? + .get(self.state.selected().ok_or(app::Error::NoRowSelected)?) + .ok_or(app::Error::OutOfBound)? .id; let state = self .items - .get(self.state.selected().ok_or(AppError::NoRowSelected)?) - .ok_or(AppError::OutOfBound)? + .get(self.state.selected().ok_or(app::Error::NoRowSelected)?) + .ok_or(app::Error::OutOfBound)? .is_stalled; let mut client = self.client.borrow_mut(); async move { @@ -268,8 +269,8 @@ impl Component for Home { KeyCode::Char('l') | KeyCode::Enter => { let id = self .items - .get(self.state.selected().ok_or(AppError::NoRowSelected)?) - .ok_or(AppError::OutOfBound)? + .get(self.state.selected().ok_or(app::Error::NoRowSelected)?) + .ok_or(app::Error::OutOfBound)? .id; return Ok(Some(Action::Mode(Mode::Properties, id))); } @@ -367,38 +368,38 @@ pub async fn close_session(client: &Rc>) -> Result (u16, u16, u16, u16, u16, u16) { let name_len = items .iter() - .map(TorrentData::formatted_name) + .map(data::Torrent::formatted_name) .map(UnicodeWidthStr::width) .min() .unwrap_or(0); let done_len = items .iter() - .map(TorrentData::percent_done) + .map(data::Torrent::percent_done) .flat_map(str::lines) .map(UnicodeWidthStr::width) .max() .unwrap_or(0); let eta_len = items .iter() - .map(TorrentData::eta) + .map(data::Torrent::eta) .map(UnicodeWidthStr::width) .max() .unwrap_or(0); let up_len = items .iter() - .map(TorrentData::upload_speed) + .map(data::Torrent::upload_speed) .map(UnicodeWidthStr::width) .max() .unwrap_or(0); let down_len = items .iter() - .map(TorrentData::download_speed) + .map(data::Torrent::download_speed) .map(UnicodeWidthStr::width) .max() .unwrap_or(0); let ratio_len = items .iter() - .map(TorrentData::ratio) + .map(data::Torrent::ratio) .map(UnicodeWidthStr::width) .max() .unwrap_or(0); diff --git a/src/components/properties.rs b/src/components/properties.rs index cd522bd..8b9da50 100644 --- a/src/components/properties.rs +++ b/src/components/properties.rs @@ -1,11 +1,8 @@ use std::{cell::RefCell, rc::Rc}; use color_eyre::Result; -use crossterm::event::{KeyCode, KeyEvent}; -use files::FilesTab; +use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use futures::executor::block_on; -use info::InfoTab; -use peers::PeersTab; use ratatui::{ layout::{Constraint, Layout, Rect}, style::{palette::tailwind, Modifier, Style, Stylize}, @@ -14,18 +11,19 @@ use ratatui::{ Frame, }; use strum::{Display, EnumIter, FromRepr, IntoEnumIterator}; -use trackers::TrackersTab; use transmission_rpc::TransClient; use crate::{ action::Action, - app::{AppError, Mode}, + app::{self, Mode}, colors::Colors, - data::{map_torrent_data, TorrentData}, + data::{self, map_torrent_data}, }; use super::{home::close_session, Component}; +const SCROLL_SIZE: usize = 4; + pub mod files; pub mod info; pub mod peers; @@ -33,8 +31,11 @@ pub mod trackers; pub struct Properties { client: Rc>, - data: TorrentData, + data: data::Torrent, selected_tab: SelectedTab, + info_tab: info::Tab, + tracker_tab: trackers::Tab, + files_tab: files::Tab, colors: Colors, } @@ -43,8 +44,8 @@ enum SelectedTab { #[default] #[strum(to_string = "Info")] Info, - #[strum(to_string = "Peers")] - Peers, + // #[strum(to_string = "Peers")] + // Peers, #[strum(to_string = "Tracker")] Tracker, #[strum(to_string = "Files")] @@ -61,7 +62,7 @@ impl Component for Properties { match action { Action::Tick => { self.data = match block_on(map_torrent_data(&self.client, Some(self.data.id))) { - Ok(d) => d.first().ok_or(AppError::OutOfBound)?.clone(), + Ok(d) => d.first().ok_or(app::Error::OutOfBound)?.clone(), Err(err) => return Ok(Some(Action::Error(err.to_string()))), }; } @@ -95,6 +96,29 @@ impl Component for Properties { KeyCode::Char('h') | KeyCode::Left => { self.previous_tab(); } + KeyCode::Char('j') | KeyCode::Down => { + self.next(); + } + KeyCode::Char('k') | KeyCode::Up => { + self.previous(); + } + KeyCode::Char('g') | KeyCode::Home => { + self.top(); + } + KeyCode::Char('G') | KeyCode::End => { + self.bottom(); + } + KeyCode::Char('u') if key.modifiers.contains(KeyModifiers::CONTROL) => { + self.scroll_up(SCROLL_SIZE); + } + KeyCode::Char('d') if key.modifiers.contains(KeyModifiers::CONTROL) => { + self.scroll_down(SCROLL_SIZE); + } + KeyCode::Enter => { + if self.selected_tab == SelectedTab::Files { + self.files_tab.toggle(); + } + } _ => {} } Ok(None) @@ -105,25 +129,76 @@ impl Properties { pub fn new(client: Rc>, id: i64) -> Result { let data = block_on(map_torrent_data(&client, Some(id)))? .first() - .ok_or(AppError::OutOfBound)? + .ok_or(app::Error::OutOfBound)? .clone(); Ok(Self { client, + info_tab: info::Tab::new(&data), + tracker_tab: trackers::Tab::new(&data), + files_tab: files::Tab::new(&data), data, selected_tab: SelectedTab::Info, colors: Colors::new(), }) } - pub fn next_tab(&mut self) { + fn next_tab(&mut self) { self.selected_tab = self.selected_tab.next(); } - pub fn previous_tab(&mut self) { + fn previous_tab(&mut self) { self.selected_tab = self.selected_tab.previous(); } - fn render_tabs(&self, frame: &mut Frame, area: Rect) { + fn next(&mut self) { + match self.selected_tab { + SelectedTab::Tracker => self.tracker_tab.next(), + SelectedTab::Files => self.files_tab.down(), + _ => {} + } + } + + fn previous(&mut self) { + match self.selected_tab { + SelectedTab::Tracker => self.tracker_tab.previous(), + SelectedTab::Files => self.files_tab.up(), + _ => {} + } + } + + fn top(&mut self) { + match self.selected_tab { + SelectedTab::Tracker => self.tracker_tab.top(), + SelectedTab::Files => self.files_tab.top(), + _ => {} + } + } + + fn bottom(&mut self) { + match self.selected_tab { + SelectedTab::Tracker => self.tracker_tab.bottom(), + SelectedTab::Files => self.files_tab.bottom(), + _ => {} + } + } + + fn scroll_down(&mut self, amount: usize) { + match self.selected_tab { + SelectedTab::Tracker => self.tracker_tab.scroll_down(amount), + SelectedTab::Files => self.files_tab.scroll_down(amount), + _ => {} + } + } + + fn scroll_up(&mut self, amount: usize) { + match self.selected_tab { + SelectedTab::Tracker => self.tracker_tab.scroll_up(amount), + SelectedTab::Files => self.files_tab.scroll_up(amount), + _ => {} + } + } + + fn render_tabs(&mut self, frame: &mut Frame, area: Rect) { let titles = SelectedTab::iter().map(SelectedTab::title); let highlight_style = Style::default() .add_modifier(Modifier::REVERSED) @@ -140,12 +215,9 @@ impl Properties { frame.render_widget(tabs, rects[0]); match self.selected_tab { - SelectedTab::Info => InfoTab::new(&self.data, &self.colors).render(frame, rects[1]), - SelectedTab::Peers => PeersTab::new(&self.data).render(frame, rects[1]), - SelectedTab::Tracker => { - TrackersTab::new(&self.data, &self.colors).render(frame, rects[1]) - } - SelectedTab::Files => FilesTab::new(&self.data).render(frame, rects[1]), + SelectedTab::Info => self.info_tab.render(frame, rects[1]), + SelectedTab::Tracker => self.tracker_tab.render(frame, rects[1]), + SelectedTab::Files => self.files_tab.render(frame, rects[1]), } } } diff --git a/src/components/properties/files.rs b/src/components/properties/files.rs index 9121ccd..a956cd5 100644 --- a/src/components/properties/files.rs +++ b/src/components/properties/files.rs @@ -1,35 +1,162 @@ -use itertools::Itertools; +use color_eyre::Result; use ratatui::{ - layout::Rect, - text::{Line, Text}, - widgets::Paragraph, + layout::{Constraint, Layout, Rect}, + style::{Modifier, Style}, + widgets::Block, Frame, }; +use tui_tree_widget::{Tree, TreeItem, TreeState}; -use super::TorrentData; +use crate::{app, colors::Colors, data}; -pub struct FilesTab<'a> { - data: &'a TorrentData, +pub struct Tab { + data: data::Torrent, + state: TreeState, + colors: Colors, } -impl<'a> FilesTab<'a> { - pub fn new(data: &'a TorrentData) -> Self { - Self { data } - } - - pub fn render(&self, frame: &mut Frame, area: Rect) { - let files = self - .data - .files - .iter() - .map(|file| { - Line::from(format!( - "{}\t{}/{}\t{}\t{}", - file.name, file.downloaded, file.total_size, file.wanted, file.priority - )) - }) - .collect_vec(); - - frame.render_widget(Paragraph::new(Text::from(files)), area); +impl Tab { + pub fn new(data: &data::Torrent) -> Self { + Self { + data: data.clone(), + state: TreeState::default(), + colors: Colors::new(), + } + } + + pub fn down(&mut self) { + self.state.key_down(); + } + pub fn up(&mut self) { + self.state.key_up(); + } + + pub fn scroll_up(&mut self, amount: usize) { + self.state.scroll_up(amount); + } + pub fn scroll_down(&mut self, amount: usize) { + self.state.scroll_up(amount); + } + + pub fn top(&mut self) { + self.state.select_first(); + } + pub fn bottom(&mut self) { + self.state.select_last(); + } + + pub fn toggle(&mut self) { + self.state.toggle_selected(); + } + + pub fn render(&mut self, frame: &mut Frame, area: Rect) { + let rects = Layout::vertical([Constraint::Min(5), Constraint::Length(3)]).split(area); + let file_style = Style::default() + .fg(self.colors.row_fg) + .bg(self.colors.buffer_bg); + let border_style = Style::default().fg(self.colors.footer_border_color); + let selected_style = Style::default() + .add_modifier(Modifier::REVERSED) + .fg(self.colors.selected_style_fg); + + let items = map_node(&parse_node( + self.data + .files + .iter() + .map(|f| { + format!( + "{}\n{}\n{}\n{}\n{}", + f.name, f.downloaded, f.total_size, f.priority, f.wanted + ) + }) + .collect(), + )); + + let tree = Tree::new(&items) + .expect("unique identifier") + .style(file_style) + .highlight_style(selected_style) + .block(Block::bordered().border_style(border_style)); + + frame.render_stateful_widget(tree, rects[0], &mut self.state); + } +} + +fn map_node(nodes: &[Node]) -> Vec> { + nodes + .iter() + .map(|node| match node { + Node::File(data::Files { + name, + downloaded, + total_size, + priority, + wanted, + }) => TreeItem::new_leaf( + name.to_string(), + format!( + "{} {} {:>10} {:>10} {:>10}", + wanted, name, downloaded, total_size, priority + ), + ), + Node::Directory(name, children) => { + TreeItem::new(name.to_string(), name.to_string(), map_node(children)) + .expect("unique identifier") + } + }) + .collect() +} + +#[derive(Debug, Clone)] +enum Node { + File(data::Files), + Directory(String, Vec), +} + +fn parse_node(paths: Vec) -> Vec { + let mut nodes: Vec = Vec::new(); + for path in paths { + let vecs = path.lines().collect::>(); + let parts = vecs.first().unwrap().split('/').collect::>(); + let data = data::Files { + name: parts.last().unwrap().to_string(), + downloaded: vecs.get(1).unwrap().parse().unwrap(), + total_size: vecs.get(2).unwrap().parse().unwrap(), + priority: vecs.get(3).unwrap().to_string(), + wanted: vecs.last().unwrap().parse().unwrap(), + }; + if !parts.is_empty() { + let _ = insert_into_tree(&mut nodes, &parts, data); + } + } + + nodes +} + +fn insert_into_tree(children: &mut Vec, parts: &[&str], data: data::Files) -> Result<()> { + let Some((current_part, remaining_parts)) = parts.split_first() else { + return Ok(()); + }; + + if remaining_parts.is_empty() { + children.push(Node::File(data)); + return Ok(()); + } + + if let Some(existing_dir) = children + .iter_mut() + .find(|n| matches!(n, Node::Directory(d_name, _) if d_name == current_part)) + { + if let Node::Directory(_, children) = existing_dir { + let _ = insert_into_tree(children, remaining_parts, data); + }; + Ok(()) + } else { + let new_dir = Node::Directory((*current_part).to_string(), Vec::new()); + children.push(new_dir); + if let Node::Directory(_, children) = children.last_mut().ok_or(app::Error::OutOfBound)? { + let _ = insert_into_tree(children, remaining_parts, data); + }; + Ok(()) } } diff --git a/src/components/properties/info.rs b/src/components/properties/info.rs index d63447b..6c15852 100644 --- a/src/components/properties/info.rs +++ b/src/components/properties/info.rs @@ -6,18 +6,19 @@ use ratatui::{ Frame, }; -use crate::colors::Colors; +use crate::{colors::Colors, data}; -use super::TorrentData; - -pub struct InfoTab<'a> { - data: &'a TorrentData, - colors: &'a Colors, +pub struct Tab { + data: data::Torrent, + colors: Colors, } -impl<'a> InfoTab<'a> { - pub fn new(data: &'a TorrentData, colors: &'a Colors) -> Self { - Self { data, colors } +impl Tab { + pub fn new(data: &data::Torrent) -> Self { + Self { + data: data.clone(), + colors: Colors::new(), + } } pub fn render(&self, frame: &mut Frame, area: Rect) { diff --git a/src/components/properties/peers.rs b/src/components/properties/peers.rs index 5136e75..10221d9 100644 --- a/src/components/properties/peers.rs +++ b/src/components/properties/peers.rs @@ -1,18 +1,18 @@ #![allow(dead_code)] use ratatui::{layout::Rect, widgets::Paragraph, Frame}; -use super::TorrentData; +use crate::data; -pub struct PeersTab<'a> { - data: &'a TorrentData, +pub struct Tab { + data: data::Torrent, } -impl<'a> PeersTab<'a> { - pub fn new(data: &'a TorrentData) -> Self { - Self { data } +impl Tab { + pub fn new(data: &data::Torrent) -> Self { + Self { data: data.clone() } } - pub fn render(self, frame: &mut Frame, area: Rect) { + pub fn render(&mut self, frame: &mut Frame, area: Rect) { frame.render_widget(Paragraph::new("Under Construction"), area); } } diff --git a/src/components/properties/trackers.rs b/src/components/properties/trackers.rs index a4f4a66..ecc7505 100644 --- a/src/components/properties/trackers.rs +++ b/src/components/properties/trackers.rs @@ -9,27 +9,83 @@ use ratatui::{ Frame, }; -use crate::colors::Colors; +use crate::{colors::Colors, data}; -use super::TorrentData; +const ITEM_HEIGHT: usize = 4; -pub struct TrackersTab<'a> { - data: &'a TorrentData, - colors: &'a Colors, +pub struct Tab { + data: data::Torrent, + colors: Colors, state: ListState, scroll_state: ScrollbarState, } -impl<'a> TrackersTab<'a> { - pub fn new(data: &'a TorrentData, colors: &'a Colors) -> Self { +impl Tab { + pub fn new(data: &data::Torrent) -> Self { Self { - data, - colors, + data: data.clone(), + colors: Colors::new(), state: ListState::default().with_selected(Some(0)), - scroll_state: ScrollbarState::new((data.trackers.len()) * 4), + scroll_state: ScrollbarState::new((data.trackers.len()) * ITEM_HEIGHT), } } + pub fn next(&mut self) { + let i = match self.state.selected() { + Some(i) => { + if i >= self.data.trackers.len() - 1 { + 0 + } else { + i + 1 + } + } + None => 0, + }; + self.state.select(Some(i)); + self.scroll_state = self.scroll_state.position(i * ITEM_HEIGHT); + } + + pub fn previous(&mut self) { + let i = match self.state.selected() { + Some(i) => { + if i == 0 { + self.data.trackers.len() - 1 + } else { + i - 1 + } + } + None => 0, + }; + self.state.select(Some(i)); + self.scroll_state = self.scroll_state.position(i * ITEM_HEIGHT); + } + + pub fn top(&mut self) { + self.state.select_first(); + self.scroll_state.first(); + } + + pub fn bottom(&mut self) { + self.state.select_last(); + self.scroll_state.last(); + } + + pub fn scroll_up(&mut self, amount: usize) { + self.state + .scroll_up_by(u16::try_from(amount).expect("failed to parse")); + self.scroll_state = self + .scroll_state + .position(self.state.selected().unwrap_or(0) * amount); + } + + pub fn scroll_down(&mut self, amount: usize) { + self.state + .scroll_down_by(u16::try_from(amount).expect("failed to parse")); + self.scroll_state = self + .scroll_state + .position(self.state.selected().unwrap_or(0) * amount); + } + pub fn render(&mut self, frame: &mut Frame, area: Rect) { let rects = Layout::vertical([Constraint::Min(5), Constraint::Length(3)]).split(area); let list_style = Style::default() diff --git a/src/components/session_stats.rs b/src/components/session_stats.rs index ba14171..5f68f8c 100644 --- a/src/components/session_stats.rs +++ b/src/components/session_stats.rs @@ -11,7 +11,7 @@ use ratatui::{ }; use transmission_rpc::{types::SessionStats, TransClient}; -use crate::{action::Action, app::AppError, colors::Colors, utils::convert_bytes}; +use crate::{action::Action, app, colors::Colors, utils::convert_bytes}; use super::Component; @@ -78,7 +78,7 @@ impl SessionStat { } } -async fn get_stats(client: Rc>) -> Result { +async fn get_stats(client: Rc>) -> Result { let res = { let mut client = client.borrow_mut(); async move { client.session_stats().await } @@ -87,6 +87,6 @@ async fn get_stats(client: Rc>) -> Result Ok(stats.arguments), - Err(err) => Err(AppError::WithMessage(err.to_string())), + Err(err) => Err(app::Error::WithMessage(err.to_string())), } } diff --git a/src/data.rs b/src/data.rs index b334782..9db6957 100644 --- a/src/data.rs +++ b/src/data.rs @@ -6,15 +6,15 @@ use itertools::Itertools; use transmission_rpc::{types::Id, TransClient}; use crate::{ - app::AppError, + app, utils::{ convert_bytes, convert_eta, convert_percentage, convert_priority, convert_status, handle_ratio, }, }; -#[derive(Clone)] -pub struct TorrentData { +#[derive(Debug, Clone)] +pub struct Torrent { pub id: i64, pub is_stalled: bool, pub status: String, @@ -35,19 +35,19 @@ pub struct TorrentData { pub eta: String, pub error: String, - pub trackers: Vec, - pub files: Vec, + pub trackers: Vec, + pub files: Vec, } -#[derive(Clone)] -pub struct TrackerData { +#[derive(Debug, Clone)] +pub struct Tracker { pub host: String, pub is_backup: bool, pub next_announce: DateTime, } -#[derive(Clone)] -pub struct FilesData { +#[derive(Debug, Clone)] +pub struct Files { pub name: String, pub downloaded: String, pub total_size: String, @@ -55,7 +55,7 @@ pub struct FilesData { pub wanted: bool, } -impl TorrentData { +impl Torrent { pub const fn ref_array(&self) -> [&String; 6] { [ &self.formatted_name, @@ -90,7 +90,7 @@ impl TorrentData { pub async fn map_torrent_data( client: &Rc>, id: Option, -) -> Result, AppError> { +) -> Result, app::Error> { let res = { let mut client = client.borrow_mut(); async move { @@ -104,7 +104,7 @@ pub async fn map_torrent_data( let torrents = match res { Ok(t) => t.arguments.torrents, - Err(err) => return Err(AppError::WithMessage(err.to_string())), + Err(err) => return Err(app::Error::WithMessage(err.to_string())), }; Ok(torrents @@ -114,7 +114,7 @@ pub async fn map_torrent_data( let trackers = t .tracker_stats? .iter() - .map(|tr| TrackerData { + .map(|tr| Tracker { host: tr.host.to_string(), is_backup: tr.is_backup, next_announce: tr.next_announce_time, @@ -126,11 +126,11 @@ pub async fn map_torrent_data( .enumerate() .filter_map(|(i, f)| { let file_stats = t.file_stats.clone()?; - Some(FilesData { + Some(Files { name: f.name.to_string(), downloaded: convert_bytes(f.bytes_completed), total_size: convert_bytes(f.length), - priority: convert_priority(file_stats.get(i)?.priority.clone()), + priority: convert_priority(&file_stats.get(i)?.priority), wanted: file_stats.get(i)?.wanted, }) }) @@ -144,12 +144,10 @@ pub async fn map_torrent_data( let status = convert_status(t.status?); let downloaded = convert_bytes(t.size_when_done? - t.left_until_done?); let size_done = convert_bytes(t.size_when_done?); - let formatted_name = format!( - "{}\nStatus: {} Have: {} of {}", - raw_name, status, downloaded, size_done - ); + let formatted_name = + format!("{raw_name}\nStatus: {status} Have: {downloaded} of {size_done}"); - Some(TorrentData { + Some(Torrent { id: t.id?, is_stalled: t.is_stalled?, status, diff --git a/src/utils.rs b/src/utils.rs index a547829..81246ab 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -26,7 +26,7 @@ pub fn handle_ratio(ratio: f32) -> String { } } -pub fn convert_priority(priority: Priority) -> String { +pub fn convert_priority(priority: &Priority) -> String { match priority { Priority::Low => "Low".to_string(), Priority::Normal => "Normal".to_string(), @@ -109,9 +109,9 @@ mod tests { #[test] fn test_convert_priority() { - assert_eq!(convert_priority(Priority::Low), "Low"); - assert_eq!(convert_priority(Priority::High), "High"); - assert_eq!(convert_priority(Priority::Normal), "Normal"); + assert_eq!(convert_priority(&Priority::Low), "Low"); + assert_eq!(convert_priority(&Priority::High), "High"); + assert_eq!(convert_priority(&Priority::Normal), "Normal"); } #[test]