diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 0e4d16b..367784d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,48 +1,47 @@ name: Rust on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] + push: + branches: ["main"] + pull_request: + branches: ["main"] env: - CARGO_TERM_COLOR: always + CARGO_TERM_COLOR: always jobs: - linux: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Build - run: cargo build --verbose --release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build + run: cargo build --verbose --release - - uses: actions/upload-artifact@v4 - with: - name: linux-x64 - path: target/release/nestdbg + - uses: actions/upload-artifact@v4 + with: + name: linux-x64 + path: target/release/nestcli windows: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - name: Build - run: cargo build --verbose --release - - - uses: actions/upload-artifact@v4 - with: - name: windows-x64 - path: target/release/nestdbg.exe + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - name: Build + run: cargo build --verbose --release + + - uses: actions/upload-artifact@v4 + with: + name: windows-x64 + path: target/release/nestcli.exe macOS: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: Build - run: cargo build --verbose --release - - - uses: actions/upload-artifact@v4 - with: - name: macOS-arm64 - path: target/release/nestdbg + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Build + run: cargo build --verbose --release + + - uses: actions/upload-artifact@v4 + with: + name: macOS-arm64 + path: target/release/nestcli diff --git a/Cargo.lock b/Cargo.lock index 33b6276..a546327 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,23 +3,36 @@ version = 4 [[package]] -name = "ahash" -version = "0.8.12" +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aes" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", - "getrandom 0.3.3", - "once_cell", - "version_check", - "zerocopy", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", ] [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -32,50 +45,83 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.8" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys", + "windows-sys 0.60.2", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", ] [[package]] name = "bitflags" -version = "2.9.1" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "regex-automata", @@ -83,25 +129,37 @@ dependencies = [ ] [[package]] -name = "bytecount" -version = "0.6.8" +name = "bumpalo" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bzip2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" +dependencies = [ + "libbz2-rs-sys", +] [[package]] name = "cc" -version = "1.2.24" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -115,11 +173,21 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" -version = "4.5.38" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -127,9 +195,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.38" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -139,9 +207,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", @@ -151,9 +219,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "clearscreen" @@ -170,29 +238,173 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags", + "crossterm_winapi", + "derive_more", + "document-features", + "mio", + "parking_lot", + "rustix 1.1.2", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] [[package]] name = "ctrlc" -version = "3.4.7" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" +checksum = "73736a89c4aff73035ba2ed2e565061954da00d4970fc9ac25dcc85a2a20d790" dependencies = [ + "dispatch2", "nix 0.30.1", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] name = "dbus" -version = "0.9.7" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" +checksum = "190b6255e8ab55a7b568df5a883e9497edc3e4821c06396612048b430e5ad1e9" dependencies = [ "libc", "libdbus-sys", - "winapi", + "windows-sys 0.59.0", +] + +[[package]] +name = "deflate64" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26bf8fc351c5ed29b5c2f0cbbac1b209b74f60ecd62e675a998df72c49af5204" + +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", ] [[package]] @@ -232,8 +444,20 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users 0.5.0", - "windows-sys", + "redox_users 0.5.2", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", ] [[package]] @@ -247,6 +471,21 @@ dependencies = [ "syn", ] +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "either" version = "1.15.0" @@ -267,12 +506,29 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.12" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + +[[package]] +name = "flate2" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +dependencies = [ + "crc32fast", + "libz-rs-sys", + "miniz_oxide", ] [[package]] @@ -283,13 +539,32 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.16" @@ -298,26 +573,26 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasip2", ] [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "heck" @@ -325,20 +600,29 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys", + "windows-sys 0.61.2", ] [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -349,9 +633,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -362,11 +646,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -377,42 +660,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -422,9 +701,9 @@ dependencies = [ [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -443,31 +722,70 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "inquire" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2628910d0114e9139056161d8644a2026be7b117f8498943f9437748b04c9e0a" +dependencies = [ + "bitflags", + "crossterm", + "dyn-clone", + "fuzzy-matcher", + "unicode-segmentation", + "unicode-width", +] + [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "libbz2-rs-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libdbus-sys" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +checksum = "5cbe856efeb50e4681f010e9aaa2bf0a644e10139e54cde10fc83a307c23bd9f" dependencies = [ "cc", "pkg-config", @@ -475,14 +793,23 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags", "libc", ] +[[package]] +name = "libz-rs-sys" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd" +dependencies = [ + "zlib-rs", +] + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -491,21 +818,52 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lzma-rust2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c60a23ffb90d527e23192f1246b14746e2f7f071cb84476dd879071696c18a4a" +dependencies = [ + "crc", + "sha2", +] [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "minimal-lexical" @@ -514,18 +872,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "nestdbg" -version = "0.3.0" +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "nestcli" +version = "0.4.0" dependencies = [ + "aho-corasick", + "anyhow", "clap", "clearscreen", "ctrlc", "directories", + "inquire", "opener", "serde", - "tabled", "toml", + "walkdir", "which 7.0.3", + "zip", ] [[package]] @@ -564,24 +948,39 @@ dependencies = [ [[package]] name = "normpath" -version = "1.3.0" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf23ab2b905654b4cb177e30b629937b3868311d4e1cba859f899c041046e69b" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "objc2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" dependencies = [ - "windows-sys", + "objc2-encode", ] [[package]] -name = "once_cell" -version = "1.21.3" +name = "objc2-encode" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "opener" @@ -593,7 +992,7 @@ dependencies = [ "dbus", "normpath", "url", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -603,23 +1002,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] -name = "papergrid" -version = "0.15.0" +name = "parking_lot" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30268a8d20c2c0d126b2b6610ab405f16517f6ba9f244d8c59ac2c512a8a1ce7" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ - "ahash", - "bytecount", - "unicode-width", + "lock_api", + "parking_lot_core", ] [[package]] -name = "percent-encoding" -version = "2.3.1" +name = "parking_lot_core" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] name = "phf" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -665,58 +1086,48 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] [[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "proc-macro-error2" -version = "2.0.1" +name = "ppmd-rust" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn", -] +checksum = "d558c559f0450f16f2a27a1f017ef38468c1090c9ce63c8e51366232d53717b4" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" @@ -733,6 +1144,15 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.6" @@ -746,20 +1166,20 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" [[package]] name = "rustix" @@ -771,36 +1191,61 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] name = "rustix" -version = "1.0.7" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -809,19 +1254,77 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[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.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +dependencies = [ + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "siphasher" version = "1.0.1" @@ -830,15 +1333,15 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "strsim" @@ -846,11 +1349,17 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" -version = "2.0.101" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -868,30 +1377,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tabled" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228d124371171cd39f0f454b58f73ddebeeef3cef3207a82ffea1c29465aea43" -dependencies = [ - "papergrid", - "tabled_derive", - "testing_table", -] - -[[package]] -name = "tabled_derive" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea5d1b13ca6cff1f9231ffd62f15eefd72543dab5e468735f1a456728a02846" -dependencies = [ - "heck", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "terminfo" version = "0.8.0" @@ -905,15 +1390,6 @@ dependencies = [ "phf_codegen", ] -[[package]] -name = "testing_table" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8daae29995a24f65619e19d8d31dea5b389f3d853d8bf297bbf607cd0014cc" -dependencies = [ - "unicode-width", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -925,11 +1401,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.17", ] [[package]] @@ -945,20 +1421,48 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -966,9 +1470,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -978,18 +1482,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", @@ -1001,31 +1505,44 @@ dependencies = [ [[package]] name = "toml_write" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -1047,18 +1564,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -1081,7 +1608,7 @@ checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" dependencies = [ "either", "env_home", - "rustix 1.0.7", + "rustix 1.1.2", "winsafe", ] @@ -1101,19 +1628,52 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", ] [[package]] @@ -1122,14 +1682,31 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -1138,53 +1715,101 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] @@ -1196,27 +1821,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -1224,9 +1845,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -1235,51 +1856,51 @@ dependencies = [ ] [[package]] -name = "zerocopy" -version = "0.8.25" +name = "zerofrom" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ - "zerocopy-derive", + "zerofrom-derive", ] [[package]] -name = "zerocopy-derive" -version = "0.8.25" +name = "zerofrom-derive" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", "syn", + "synstructure", ] [[package]] -name = "zerofrom" -version = "0.1.6" +name = "zeroize" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ - "zerofrom-derive", + "zeroize_derive", ] [[package]] -name = "zerofrom-derive" -version = "0.1.6" +name = "zeroize_derive" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", "syn", - "synstructure", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -1288,9 +1909,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -1299,11 +1920,84 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zip" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b" +dependencies = [ + "aes", + "arbitrary", + "bzip2", + "constant_time_eq", + "crc32fast", + "deflate64", + "flate2", + "getrandom 0.3.4", + "hmac", + "indexmap", + "lzma-rust2", + "memchr", + "pbkdf2", + "ppmd-rust", + "sha1", + "time", + "zeroize", + "zopfli", + "zstd", +] + +[[package]] +name = "zlib-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 825ea6a..21fa6af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "nestdbg" -version = "0.3.0" +name = "nestcli" +version = "0.4.0" edition = "2024" authors = ["TurtleP"] license = "MIT" -description = "A simple remote debugging tool for LÖVE Potion games." +description = "A simple CLI tool for LÖVE Potion games." readme = "README.md" homepage = "https://github.com/TurtleP/nestdbg" repository = "https://github.com/TurtleP/nestdbg" @@ -12,15 +12,19 @@ keywords = ["cli", "debug"] categories = ["command-line-utilities"] [dependencies] +aho-corasick = "1.1.3" +anyhow = "1.0.100" clap = { version = "4.5.18", features = ["derive"] } clearscreen = "3.0.0" ctrlc = "3.4.6" directories = "6.0.0" +inquire = "0.9.1" opener = { version = "0.7.2", features = ["reveal"] } serde = { version = "1.0.215", default-features = false, features = ["derive"] } -tabled = "0.19.0" toml = "0.8.22" +walkdir = "2.5.0" which = "7.0.3" +zip = "6.0.0" [profile.release] lto = "fat" diff --git a/LICENSE b/LICENSE index febac06..f5a827b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2025 Serena Postelnek - -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. +MIT License + +Copyright (c) 2025 Serena Postelnek + +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/README.md b/README.md index 2b3ac56..1f69438 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,45 @@ - -# nestdbg - -`nestdbg` is a remote debugging tool for [LÖVE Potion](https://github.com/lovebrew/lovepotion) games, designed to streamline the development process by providing a command-line interface for managing and connecting to debug targets over a network. - -#### Command Line - -``` -Remote debugging tool for LÖVE Potion games. - -Usage: nestdbg.exe - -Commands: - add Add a new connection - remove Remove an existing connection [aliases: rm] - open-config Open the configuration file in the file browser - list List all connections - connect Connect to a target using an existing connection or IP address - addr2line Resolve exception addresses using a debug binary - help Print this message or the help of the given subcommand(s) - -Options: - -h, --help Print help - -V, --version Print version -``` - -## Installation - -> [!IMPORTANT] -> The project is built using the rust programming language. Ensure that it is installed before trying to build the project. - - -**1. Clone the repository** - -```bash -git clone https://github.com/TurtleP/nestdbg -cd nestdbg -``` - -**2. Build the project in release mode** -```bash -cargo build --release -``` - -**3. Install the binary locally** -```bash -cargo install --path . -``` - -Alternatively, install the tool through crates.io: -```bash -cargo install nestdbg -``` + +# nestcli + +`nestcli` is a command-line tool for [LÖVE Potion](https://github.com/lovebrew/lovepotion) games, designed to streamline the development process by providing a command-line interface for managing and connecting to debug targets over a network. + +#### Command Line + +``` +A simple CLI tool for LÖVE Potion games. + +Usage: nestcli.exe + +Commands: + config Add, remove, or list configured target devices + debug Tools for debugging builds and resolving symbols + bundle Bundle utilization commands + help Print this message or the help of the given subcommand(s) + +Options: + -h, --help Print help + -V, --version Print version +``` + +## Installation + +> [!IMPORTANT] +> The project is built using the rust programming language. Ensure that it is installed before trying to build the project. + + +**1. Clone the repository** + +```bash +git clone https://github.com/TurtleP/nestdbg +cd nestdbg +``` + +**2. Install the binary locally** +```bash +cargo install --path . +``` + +Alternatively, install the tool through crates.io: +```bash +cargo install nestcli +``` diff --git a/src/addr2line.rs b/src/addr2line.rs deleted file mode 100644 index d1887f4..0000000 --- a/src/addr2line.rs +++ /dev/null @@ -1,119 +0,0 @@ -use std::fs::File; -use std::io::{BufReader, Read}; -use std::path::{Path, PathBuf}; -use std::process::Command; - -use which::which; - -#[derive(Debug)] -struct Candidate { - binary: &'static str, - magic: &'static [u8], - args: &'static [&'static str], - search_path: &'static str, -} - -impl Candidate { - fn matches(&self, filepath: &Path) -> bool { - if self.magic.is_empty() { - return false; - } - - let file = match File::open(filepath) { - Ok(f) => f, - Err(_) => return false, - }; - let mut reader = BufReader::new(file); - - const CHUNK: usize = 8 * 1024; - let mut buffer = vec![0u8; CHUNK]; - let mut overlap: Vec = Vec::new(); - let keep = self.magic.len().saturating_sub(1); - - loop { - let n = match reader.read(&mut buffer) { - Ok(0) => break, - Ok(n) => n, - Err(_) => return false, - }; - let mut window = Vec::with_capacity(overlap.len() + n); - window.extend_from_slice(&overlap); - window.extend_from_slice(&buffer[..n]); - if window.windows(self.magic.len()).any(|w| w == self.magic) { - return true; - } - overlap.clear(); - let total = window.len(); - if keep > 0 && total >= keep { - overlap.extend_from_slice(&window[total - keep..]); - } else if total < keep { - overlap.extend_from_slice(&window); - } - } - false - } - - fn command(&self, filepath: &Path, addresses: &[String]) { - let base_dir = match std::env::var("DEVKITPRO") { - Ok(val) => PathBuf::from(val), - Err(_) => { - eprintln!("DEVKITPRO environment variable is not set."); - return; - } - }; - - let binary_path = base_dir.join(Path::new(self.search_path).join(self.binary)); - println!("Using addr2line binary at: {}", binary_path.display()); - if which(&binary_path).is_err() { - eprintln!("Could not find {} in {}", self.binary, self.search_path); - return; - } - - let mut command = Command::new(binary_path); - command - .arg("-aipfCe") - .arg(self.args.join(" ")) - .arg("-e") - .arg(filepath); - - for addr in addresses { - command.arg(addr); - } - - match command.output() { - Ok(output) => println!("{}", String::from_utf8_lossy(&output.stdout)), - Err(e) => eprintln!("Failed to execute {}: {}", self.binary, e), - } - } -} - -static CANDIDATES: &[Candidate] = &[ - Candidate { - binary: "arm-none-eabi-addr2line", - magic: b"3dsx_crt0.o", - args: &["arm"], - search_path: "devkitARM/bin", - }, - Candidate { - binary: "aarch64-none-elf-addr2line", - magic: b"switch_crt0.o", - args: &[""], - search_path: "devkitA64/bin", - }, - Candidate { - binary: "powerpc-eabi-addr2line", - magic: b"crt0_rpx.o", - args: &[""], - search_path: "devkitPPC/bin", - }, -]; - -pub fn run(filepath: &PathBuf, addresses: Vec) { - match CANDIDATES.iter().find(|c| c.matches(filepath)) { - Some(candidate) => candidate.command(filepath, &addresses), - None => println!( - "No suitable addr2line found for the given file: {}", - filepath.display() - ), - } -} diff --git a/src/commands.rs b/src/commands.rs deleted file mode 100644 index 1212320..0000000 --- a/src/commands.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::net::Ipv4Addr; -use std::path::PathBuf; - -use clap::Parser; -use clap::Subcommand; - -#[derive(Parser, Debug)] -#[command( - version, - about = "Remote debugging tool for LÖVE Potion games.", - author = "support@lovebrew.org" -)] -pub struct Cli { - #[command(subcommand)] - pub command: Command, -} - -#[derive(Subcommand, Debug)] -pub enum Command { - /// Add a new connection - Add { - #[arg(help = "Name to assign to this connection")] - name: String, - #[arg(help = "IP address of the target")] - address: Ipv4Addr, - }, - /// Remove an existing connection - #[command(visible_alias = "rm", alias = "delete")] - Remove { - #[arg(help = "Name of the connection to remove")] - name: String, - }, - /// Open the configuration file in the file browser - OpenConfig, - /// List all connections - List, - /// Connect to a target using an existing connection or IP address - Connect { - #[arg(help = "IP address or name of the target")] - target: String, - #[arg(long, help = "File to write logging output to")] - file: Option, - }, - /// Resolve exception addresses using a debug binary - Addr2line { - #[arg(help = "Path to the debug binary")] - filepath: PathBuf, - #[arg(help = "Exception addresses to resolve")] - addresses: Vec, - }, -} diff --git a/src/commands/bundle.rs b/src/commands/bundle.rs new file mode 100644 index 0000000..ba82268 --- /dev/null +++ b/src/commands/bundle.rs @@ -0,0 +1,19 @@ +use anyhow::Result; +use clap::Subcommand; + +use crate::services::bundle::{generate_bundle_config, zip_bundle}; + +#[derive(Subcommand, Debug)] +pub enum BundleCmd { + /// Initialize a Bundle configuration file + Init, + /// Create a Bundle from the configuration file + Create, +} + +pub fn handle_bundle(command: BundleCmd) -> Result<()> { + match command { + BundleCmd::Init => generate_bundle_config(), + BundleCmd::Create => zip_bundle(), + } +} diff --git a/src/commands/conn.rs b/src/commands/conn.rs new file mode 100644 index 0000000..90c4388 --- /dev/null +++ b/src/commands/conn.rs @@ -0,0 +1,28 @@ +use anyhow::Result; +use clap::Subcommand; +use std::net::Ipv4Addr; + +use crate::config::app::Config; + +#[derive(Subcommand, Debug)] +pub enum ConfigCmd { + /// Add a new connection + Add { name: String, addr: Ipv4Addr }, + /// Remove a connection + #[command(visible_alias = "rm", aliases = ["delete", "del"])] + Remove { name: String }, + /// List all connections + #[command(visible_alias = "ls", aliases = ["show", "all"])] + List, + /// Open the directory to the config file + Open, +} + +pub fn handle_connection(command: ConfigCmd, mut config: Config) -> Result<()> { + match command { + ConfigCmd::Add { name, addr } => config.add(&name, addr), + ConfigCmd::Remove { name } => config.remove(&name), + ConfigCmd::List => config.list(), + ConfigCmd::Open => config.reveal(), + } +} diff --git a/src/commands/debug.rs b/src/commands/debug.rs new file mode 100644 index 0000000..a920ae9 --- /dev/null +++ b/src/commands/debug.rs @@ -0,0 +1,48 @@ +use std::{ + io::{Write, stdout}, + net::Ipv4Addr, +}; + +use anyhow::Result; +use clap::Subcommand; + +use crate::config::app::Config; +use crate::models::socket::Socket; +use crate::platforms::addr2line::find_candidate; + +#[derive(Subcommand)] +pub enum DebugCmd { + /// Attach to a remote target + Attach { address: String }, + /// Debug a local binary using addr2line + Addr2line { + filepath: String, + addresses: Vec, + }, +} + +pub fn handle_debug(command: DebugCmd, config: Config) -> Result<()> { + match command { + DebugCmd::Attach { address } => { + let target = match config.get(&address) { + Some(addr) => *addr, + None => address.parse::()?, + }; + let mut socket = Socket::new((target, config.get_port()))?; + while let Some(data) = socket.read()? { + stdout().write_all(data)?; + } + } + DebugCmd::Addr2line { + filepath, + addresses, + } => { + let filepath = std::path::absolute(filepath)?; + let candidate = find_candidate(&filepath)?; + if let Some(candidate) = candidate { + candidate.command(&filepath, &addresses)?; + } + } + } + Ok(()) +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..99c1b57 --- /dev/null +++ b/src/commands/mod.rs @@ -0,0 +1,3 @@ +pub mod bundle; +pub mod conn; +pub mod debug; diff --git a/src/config.rs b/src/config.rs deleted file mode 100644 index ae4e140..0000000 --- a/src/config.rs +++ /dev/null @@ -1,130 +0,0 @@ -use directories::ProjectDirs; -use serde::{Deserialize, Serialize}; -use tabled::settings::Style; -use tabled::{Table, Tabled}; - -use std::collections::BTreeMap; -use std::fs; -use std::io::{Error, ErrorKind, Result}; -use std::net::Ipv4Addr; -use std::path::PathBuf; - -#[derive(Debug, Serialize, Deserialize, Default)] -pub struct ConnectionConfig { - pub connections: BTreeMap, -} - -#[derive(Tabled)] -struct ConnectionRow { - name: String, - address: Ipv4Addr, -} - -const CONFIG_FILE_NAME: &str = "connections.toml"; - -impl ConnectionConfig { - /// Load the connection configuration from the file system. - /// If the file does not exist or is invalid, return a default configuration. - /// The connections are sorted by name after loading. - pub fn load() -> Self { - let path = match Self::get_filepath() { - Ok(path) => path, - Err(_) => return ConnectionConfig::default(), - }; - - if !path.exists() { - return ConnectionConfig::default(); - } - - if let Ok(content) = fs::read_to_string(path) { - return toml::from_str::(&content).unwrap_or_default(); - } - ConnectionConfig::default() - } - - /// Get the file path for the connection configuration file. - /// This will create the directory if it does not exist. - pub fn get_filepath() -> Result { - match ProjectDirs::from("com", "lovebrew", "nestdbg") { - Some(proj_dirs) => { - let config_dir = proj_dirs.config_dir(); - fs::create_dir_all(config_dir)?; - Ok(config_dir.join(CONFIG_FILE_NAME)) - } - None => Err(Error::new( - ErrorKind::NotFound, - "Could not find project directories", - )), - } - } - - /// List all connections in a table format. - /// If no connections are found, it will print a message indicating that. - pub fn list_connections(&self) { - if self.connections.is_empty() { - return println!("No connections found."); - } - - let collection: Vec = self - .connections - .iter() - .map(|(name, &address)| ConnectionRow { - name: name.clone(), - address, - }) - .collect(); - - let mut table = Table::new(collection); - table.with(Style::markdown()); - - println!("{table}"); - } - - /// Resolve a target by name or IP address. - pub fn resolve_target(&self, target: impl ToString) -> Option<(Ipv4Addr, u16)> { - let connection = self - .connections - .iter() - .find(|(name, _)| name.to_string() == target.to_string()); - - /* grab the Ipv4Addr from Connection */ - if let Some(data) = connection { - return Some((*data.1, 8000)); - } - - /* parse the address from the string */ - Some((target.to_string().parse().ok()?, 8000)) - } - - /// Add a new connection to the configuration. - pub fn add_connection(&mut self, name: impl ToString, address: Ipv4Addr) -> Result<()> { - self.connections.insert(name.to_string(), address); - self.save() - } - - /// Remove a connection by name. - /// Returns `Ok(true)` if the connection was found and removed, `Ok(false)` if not found. - pub fn remove_connection(&mut self, filter: &str) -> Result { - if self.connections.iter().any(|(name, _)| filter == name) { - self.connections.remove(filter); - self.save()?; - Ok(true) - } else { - Ok(false) - } - } - - /// Save the current configuration to the file system. - pub fn save(&self) -> Result<()> { - let path = Self::get_filepath()?; - - if !path.exists() { - fs::create_dir_all(path.parent().unwrap())?; - } - - match toml::to_string_pretty(self) { - Ok(content) => fs::write(path, content), - Err(e) => Err(Error::new(ErrorKind::InvalidData, e)), - } - } -} diff --git a/src/config/app.rs b/src/config/app.rs new file mode 100644 index 0000000..0f1c0e9 --- /dev/null +++ b/src/config/app.rs @@ -0,0 +1,105 @@ +use std::collections::BTreeMap; +use std::fs; +use std::net::Ipv4Addr; +use std::path::PathBuf; + +use anyhow::{Result, bail}; +use directories::ProjectDirs; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct SocketConfig { + default_port: u16, +} + +impl Default for SocketConfig { + fn default() -> Self { + Self { default_port: 8000 } + } +} + +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct Config { + connections: BTreeMap, + socket: SocketConfig, +} + +const QUALIFIER: &str = "com"; +const ORGANIZATION: &str = "lovebrew"; +const APPLICATION: &str = "nestcli"; + +const FILE_NAME: &str = "config.toml"; + +impl Config { + pub fn path() -> Result { + let dirs = ProjectDirs::from(QUALIFIER, ORGANIZATION, APPLICATION); + if let Some(dirs) = dirs { + return Ok(dirs.config_dir().join(FILE_NAME)); + } + bail!("Failed to get project directories") + } + + pub fn reveal(&self) -> Result<()> { + let path = Self::path()?; + if let Some(parent) = path.parent() { + opener::reveal(parent)?; + } + Ok(()) + } + + pub fn add(&mut self, name: &str, address: Ipv4Addr) -> Result<()> { + if name.is_empty() { + bail!("Name cannot be empty"); + } + let value = self.connections.insert(name.to_string(), address); + println!( + "Connection '{name}' {}", + value.map_or("added", |_| "updated") + ); + self.save() + } + + pub fn get_port(&self) -> u16 { + self.socket.default_port + } + + pub fn remove(&mut self, name: &str) -> Result<()> { + if self.connections.remove(name).is_some() { + println!("Connection '{name}' removed"); + self.save()?; + } + Ok(()) + } + + pub fn get(&self, name: &str) -> Option<&Ipv4Addr> { + self.connections.get(name) + } + + pub fn list(&self) -> Result<()> { + println!("{:<10} Address", "Name"); + for (name, addr) in &self.connections { + println!("{name:<10} {addr}"); + } + Ok(()) + } + + pub fn load() -> Result { + let path = Self::path()?; + if !path.exists() { + return Ok(Self::default()); + } + let content = fs::read_to_string(path)?; + let config = toml::from_str(&content)?; + Ok(config) + } + + pub fn save(&self) -> Result<()> { + let path = Self::path()?; + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + let content = toml::to_string_pretty(self)?; + fs::write(path, content)?; + Ok(()) + } +} diff --git a/src/config/bundle.rs b/src/config/bundle.rs new file mode 100644 index 0000000..26283c5 --- /dev/null +++ b/src/config/bundle.rs @@ -0,0 +1,59 @@ +use std::{collections::HashMap, str::FromStr}; + +use serde::{Deserialize, Serialize}; + +pub const CONFIG_NAME: &str = "lovebrew.toml"; + +#[derive(Serialize, Deserialize, PartialEq, Eq, Hash)] +#[serde(rename_all = "lowercase")] +pub enum PlatformTarget { + Ctr, + Hac, + Cafe, +} + +impl FromStr for PlatformTarget { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "ctr" => Ok(Self::Ctr), + "hac" => Ok(Self::Hac), + "cafe" => Ok(Self::Cafe), + _ => Err("No such match".into()), + } + } +} + +#[derive(Serialize, Deserialize, Default)] +pub struct Metadata { + pub name: String, + pub author: String, + pub description: String, + pub version: String, + pub icons: HashMap, +} + +impl Metadata { + pub fn set_icon(&mut self, platform: PlatformTarget, path: &str) { + self.icons.insert(platform, String::from(path)); + } +} + +#[derive(Serialize, Deserialize, Default)] +pub struct Build { + pub targets: Vec, + pub source: String, + pub packaged: bool, +} + +impl Build { + pub fn has_target(&self, target: PlatformTarget) -> bool { + self.targets.contains(&target) + } +} + +#[derive(Serialize, Deserialize)] +pub struct BundleConfig { + pub metadata: Metadata, + pub build: Build, +} diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..09a63c4 --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,2 @@ +pub mod app; +pub mod bundle; diff --git a/src/main.rs b/src/main.rs index 9c3f0c6..6e731b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,82 +1,54 @@ -use clap::{Error, Parser}; - -use std::{net::Ipv4Addr, path::PathBuf}; - -mod addr2line; mod commands; mod config; -mod output_writer; -mod socket; - -use commands::{Cli, Command}; -use config::ConnectionConfig; -use output_writer::OutputWriter; -use socket::Socket; - -fn connect_to_target(address: (Ipv4Addr, u16), file: Option) -> Result<(), Error> { - println!("Connecting to target at {}...", address.0); - let mut socket = Socket::new(address)?; - - clearscreen::clear().expect("Failed to clear the screen."); - - let mut file = OutputWriter::new(file)?; - - loop { - match socket.read() { - Ok(data_read) => { - if data_read.is_empty() { - break; - } - - file.write(data_read)?; - } - Err(e) => { - eprintln!("Failed to read from the socket: {}", e); - break; - } - } - } - - Ok(()) +mod models; +mod platforms; +mod prompts; +mod services; + +use anyhow::Result; +use clap::{Parser, Subcommand}; +use commands::{bundle::BundleCmd, conn::ConfigCmd, debug::DebugCmd}; +use config::app::Config; + +use commands::{bundle::handle_bundle, conn::handle_connection, debug::handle_debug}; + +#[derive(Parser)] +#[command(author="support@lovebrew.org", version, about, long_about = None)] +#[command(name = "nestcli")] +struct Cli { + #[command(subcommand)] + command: Commands, } -fn main() -> Result<(), Error> { - let mut config = ConnectionConfig::load(); +#[derive(Subcommand)] +enum Commands { + /// Add, remove, or list configured target devices + #[command(alias = "c")] + Config { + #[command(subcommand)] + command: ConfigCmd, + }, + /// Tools for debugging builds and resolving symbols + #[command(alias = "dbg")] + Debug { + #[command(subcommand)] + command: DebugCmd, + }, + /// Bundle utilization commands + #[command(alias = "b")] + Bundle { + #[command(subcommand)] + command: BundleCmd, + }, +} - let args = Cli::parse(); +fn main() -> Result<()> { + let cli = Cli::parse(); + let config = Config::load()?; - match args.command { - Command::Add { name, address } => { - config.add_connection(&name, address)?; - println!("Connection '{}' added for target '{}'.", name, address); - } - Command::Remove { name } => { - if config.remove_connection(&name)? { - println!("Connection '{}' removed.", name); - } else { - eprintln!("No connection found with the name '{}'.", name); - } - } - Command::OpenConfig => { - let _ = opener::reveal(&ConnectionConfig::get_filepath()?); - } - Command::List => config.list_connections(), - Command::Connect { target, file } => { - if let Some(address) = config.resolve_target(&target) { - if connect_to_target(address, file).is_err() { - eprintln!("Failed to connect to the target."); - } - } else { - eprintln!("No connection found for target '{}'.", target); - } - } - Command::Addr2line { - filepath, - addresses, - } => { - addr2line::run(&filepath, addresses); - } + match cli.command { + Commands::Config { command } => handle_connection(command, config), + Commands::Debug { command } => handle_debug(command, config), + Commands::Bundle { command } => handle_bundle(command), } - - Ok(()) } diff --git a/src/models/bundle.rs b/src/models/bundle.rs new file mode 100644 index 0000000..e165d67 --- /dev/null +++ b/src/models/bundle.rs @@ -0,0 +1,117 @@ +use std::fs::File; +use std::path::{Path, PathBuf}; + +use anyhow::Result; +use walkdir::WalkDir; +use zip::ZipWriter; +use zip::write::SimpleFileOptions; + +use crate::config::bundle::{BundleConfig, CONFIG_NAME}; + +const BUNDLE_NAME: &str = "bundle.zip"; +const IGNORE_NAME: &str = ".bundleignore"; + +const IGNORE_DATA: &[&str; 7] = &[ + ".git", + ".gitignore", + ".gitattributes", + ".gitmodules", + ".hg", + ".svn", + "bundle.zip", +]; + +pub struct Bundle { + cwd: PathBuf, + config: BundleConfig, + zip: ZipWriter, + options: SimpleFileOptions, + root_includes: Vec, +} + +impl Bundle { + pub fn new(config: BundleConfig) -> Result { + let cwd = std::env::current_dir()?; + + if Path::new(BUNDLE_NAME).exists() { + std::fs::remove_file(BUNDLE_NAME)?; + } + + let file = File::create(BUNDLE_NAME)?; + let zip = ZipWriter::new(file); + let options = SimpleFileOptions::default(); + let root_includes = Vec::new(); + + Ok(Self { + cwd, + config, + zip, + options, + root_includes, + }) + } + + fn collect_root_includes(&mut self) { + let config = &self.config; + + let mut includes = Vec::new(); + includes.push(self.cwd.join(CONFIG_NAME)); + + if Path::new(&self.cwd).join(IGNORE_NAME).exists() { + includes.push(self.cwd.join(IGNORE_NAME)); + } + + for path in config.metadata.icons.values() { + if Path::new(&self.cwd).join(path).exists() { + includes.push(self.cwd.join(path)); + } + } + + includes.sort(); + includes.dedup(); + self.root_includes = includes; + } + + pub fn add_tree(&mut self) -> Result<()> { + self.collect_root_includes(); + + let cwd = &self.cwd; + let game_dir = Path::new(&self.config.build.source); + + let walker = WalkDir::new(cwd).into_iter().filter_entry(|entry| { + if let Some(name) = entry.file_name().to_str() { + return !IGNORE_DATA.contains(&name); + } + true + }); + + for entry in walker.filter_map(|entry| entry.ok()) { + let zip_path = entry.path().strip_prefix(cwd)?; + if zip_path.as_os_str().is_empty() { + continue; + } + + let is_root_file = self.root_includes.contains(&entry.path().into()); + let file_path = if is_root_file { + zip_path.to_owned() + } else { + game_dir.join(zip_path) + }; + + if entry.path().is_file() { + let mut file = File::open(entry.path())?; + self.zip.start_file_from_path(file_path, self.options)?; + std::io::copy(&mut file, &mut self.zip)?; + } else { + self.zip.add_directory_from_path(file_path, self.options)?; + } + } + Ok(()) + } + + pub fn finish(self) -> Result<()> { + self.zip.finish()?; + println!("{BUNDLE_NAME} created successfully."); + Ok(()) + } +} diff --git a/src/models/mod.rs b/src/models/mod.rs new file mode 100644 index 0000000..5d786c9 --- /dev/null +++ b/src/models/mod.rs @@ -0,0 +1,2 @@ +pub mod bundle; +pub mod socket; diff --git a/src/models/socket.rs b/src/models/socket.rs new file mode 100644 index 0000000..1f5ebde --- /dev/null +++ b/src/models/socket.rs @@ -0,0 +1,36 @@ +use std::{ + io::{Read, Result}, + net::{Ipv4Addr, Shutdown, TcpStream}, +}; + +pub struct Socket { + stream: TcpStream, + buffer: Vec, +} + +const SOCKET_BUFFER_SIZE: usize = 0x1000; + +impl Drop for Socket { + fn drop(&mut self) { + if let Err(result) = self.stream.shutdown(Shutdown::Both) { + eprintln!("Failed to shutdown socket: {result}"); + } + } +} + +impl Socket { + pub fn new(address: (Ipv4Addr, u16)) -> Result { + let stream = TcpStream::connect(address)?; + println!("Attaching to remote target at {}", address.0); + let buffer = vec![0; SOCKET_BUFFER_SIZE]; + Ok(Self { stream, buffer }) + } + + pub fn read(&mut self) -> Result> { + match self.stream.read(&mut self.buffer) { + Ok(0) => Ok(None), + Ok(n) => Ok(Some(&self.buffer[..n])), + Err(e) => Err(e), + } + } +} diff --git a/src/output_writer.rs b/src/output_writer.rs deleted file mode 100644 index 4ea35cd..0000000 --- a/src/output_writer.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::fs::File; -use std::io::{Result, Write, stdout}; -use std::path::PathBuf; - -pub struct OutputWriter { - file: Option, -} - -impl Drop for OutputWriter { - fn drop(&mut self) { - if let Some(ref mut file) = self.file { - if let Err(e) = file.flush() { - eprintln!("Failed to flush log file: {}", e); - } - } - } -} - -impl OutputWriter { - pub fn new(path: Option) -> Result { - if let Some(path) = path { - let file = File::create(path)?; - return Ok(OutputWriter { file: Some(file) }); - } - Ok(OutputWriter { file: None }) - } - - pub fn write(&mut self, data: &[u8]) -> Result<()> { - if let Some(ref mut file) = self.file { - return file.write_all(data); - } - - stdout().write_all(data)?; - Ok(()) - } -} diff --git a/src/platforms/addr2line.rs b/src/platforms/addr2line.rs new file mode 100644 index 0000000..6b8aeec --- /dev/null +++ b/src/platforms/addr2line.rs @@ -0,0 +1,97 @@ +use std::fs::File; +use std::io::{BufReader, Write, stdout}; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use aho_corasick::AhoCorasick; +use anyhow::Result; + +pub struct Candidate { + binary: &'static str, + pub magic: &'static [u8], + args: &'static [&'static str], + search_path: &'static str, + device: &'static str, +} + +const CANDIDATES: [Candidate; 3] = [ + Candidate { + binary: "arm-none-eabi-addr2line", + magic: b"3dsx_crt0.o", + args: &["arm"], + search_path: "devkitARM/bin", + device: "Nintendo 3DS", + }, + Candidate { + binary: "aarch64-none-elf-addr2line", + magic: b"switch_crt0.o", + args: &[""], + search_path: "devkitA64/bin", + device: "Nintendo Switch", + }, + Candidate { + binary: "powerpc-eabi-addr2line", + magic: b"crt0_rpx.o", + args: &[""], + search_path: "devkitPPC/bin", + device: "Nintendo Wiiᵘ", + }, +]; + +pub fn find_candidate(filepath: &Path) -> Result> { + let reader = match File::open(filepath) { + Ok(file) => BufReader::new(file), + Err(_) => anyhow::bail!("Failed to open file: {filepath:#?}"), + }; + + let patterns = CANDIDATES.iter().map(|c| c.magic).collect::>(); + let ac = AhoCorasick::new(&patterns)?; + + if let Some(matched) = ac.stream_find_iter(reader).flatten().next() { + let index = matched.pattern().as_usize(); + return Ok(Some(&CANDIDATES[index])); + } + Ok(None) +} + +impl Candidate { + pub fn command(&self, filepath: &Path, addresses: &[String]) -> Result<()> { + if !filepath.exists() || !filepath.is_file() { + anyhow::bail!("File not found: {filepath:#?}"); + } + + if addresses.is_empty() { + anyhow::bail!("No addresses provided"); + } + + let binary_name = match std::env::var("DEVKITPRO") { + Ok(val) => PathBuf::from(val).join(self.search_path).join(self.binary), + Err(_) => PathBuf::from(self.binary), + }; + + if which::which(&binary_name).is_err() { + anyhow::bail!("{} not found", self.binary); + } + + println!("[{}: {}]", self.device, self.binary); + + let mut command = Command::new(binary_name); + command + .arg("-aipfCe") + .args(self.args) + .arg("-e") + .arg(filepath); + + for address in addresses { + command.arg(address); + } + + let output = match command.output() { + Ok(output) => output.stdout, + Err(e) => anyhow::bail!("Failed to execute addr2line: {e}"), + }; + + stdout().write_all(&output)?; + Ok(()) + } +} diff --git a/src/platforms/mod.rs b/src/platforms/mod.rs new file mode 100644 index 0000000..dd7c17c --- /dev/null +++ b/src/platforms/mod.rs @@ -0,0 +1 @@ +pub mod addr2line; diff --git a/src/prompts/bundle.rs b/src/prompts/bundle.rs new file mode 100644 index 0000000..433f6f5 --- /dev/null +++ b/src/prompts/bundle.rs @@ -0,0 +1,42 @@ +#[macro_export] +macro_rules! txt { + ($prompt:expr, $default:expr) => { + ::inquire::Text::new($prompt) + .with_default($default) + .prompt()? + }; +} + +#[macro_export] +macro_rules! multiselect { + ($prompt:expr, $opts:expr) => {{ + // validator enforces at least one selection + ::inquire::MultiSelect::new($prompt, $opts) + .with_validator(|s: &[::inquire::list_option::ListOption<&&str>]| { + if s.is_empty() { + Ok(::inquire::validator::Validation::Invalid( + "Select at least one option".into(), + )) + } else { + Ok(::inquire::validator::Validation::Valid) + } + }) + .prompt()? + .into_iter() + .map(|s| { + s.to_string() + .parse::() + .expect("invalid platform target") + }) + .collect::>() + }}; +} + +#[macro_export] +macro_rules! confirm { + ($prompt:expr, $help:expr) => { + ::inquire::Confirm::new($prompt) + .with_help_message($help) + .prompt()? + }; +} diff --git a/src/prompts/mod.rs b/src/prompts/mod.rs new file mode 100644 index 0000000..983f2dd --- /dev/null +++ b/src/prompts/mod.rs @@ -0,0 +1 @@ +pub(crate) mod bundle; diff --git a/src/services/bundle.rs b/src/services/bundle.rs new file mode 100644 index 0000000..c0e20ea --- /dev/null +++ b/src/services/bundle.rs @@ -0,0 +1,65 @@ +use std::collections::HashMap; +use std::path::Path; + +use crate::config::bundle::{Build, BundleConfig, CONFIG_NAME, Metadata, PlatformTarget}; +use crate::models::bundle::Bundle; +use crate::{confirm, multiselect, txt}; + +use anyhow::Result; + +pub fn generate_bundle_config() -> Result<()> { + let mut metadata = Metadata { + name: txt!("Enter game title:", "SuperGame"), + author: txt!("Enter author name:", "SuperAuthor"), + description: txt!("Enter game description:", "SuperDescription"), + version: txt!("Enter game version:", "0.1.0"), + icons: HashMap::new(), + }; + + let targets = vec!["ctr", "hac", "cafe"]; + + let build = Build { + targets: multiselect!("Select build targets:", targets), + source: txt!("Enter source directory:", "src"), + packaged: confirm!( + "Package the builds?", + "If yes, the targets will be compiled to binary formats" + ), + }; + + if build.has_target(PlatformTarget::Ctr) { + let path = txt!("Nintendo 3DS icon path:", "icon48.png"); + metadata.set_icon(PlatformTarget::Ctr, &path); + } + + if build.has_target(PlatformTarget::Hac) { + let path = txt!("Nintendo Switch icon path:", "icon256.jpg"); + metadata.set_icon(PlatformTarget::Hac, &path); + } + + if build.has_target(PlatformTarget::Cafe) { + let path = txt!("Nintendo Wiiᵘ icon path:", "icon128.png"); + metadata.set_icon(PlatformTarget::Cafe, &path); + } + + let bundle_config = BundleConfig { metadata, build }; + let contents = toml::to_string(&bundle_config)?; + std::fs::write(CONFIG_NAME, contents)?; + println!("{} created successfully", CONFIG_NAME); + + Ok(()) +} + +pub fn zip_bundle() -> Result<()> { + let cwd = std::env::current_dir()?; + if !Path::new(CONFIG_NAME).exists() { + anyhow::bail!("Could not find `{CONFIG_NAME}` in `{}`", cwd.display()); + } + + let config_contents = std::fs::read_to_string(CONFIG_NAME)?; + let config = toml::from_str::(&config_contents)?; + + let mut bundle = Bundle::new(config)?; + bundle.add_tree()?; + bundle.finish() +} diff --git a/src/services/mod.rs b/src/services/mod.rs new file mode 100644 index 0000000..a02d5e6 --- /dev/null +++ b/src/services/mod.rs @@ -0,0 +1 @@ +pub mod bundle; diff --git a/src/socket.rs b/src/socket.rs deleted file mode 100644 index ed22f06..0000000 --- a/src/socket.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::{ - io::{Error, Read}, - net::{Ipv4Addr, Shutdown, TcpStream}, -}; - -pub struct Socket { - stream: TcpStream, - buffer: Vec, -} - -impl Drop for Socket { - fn drop(&mut self) { - if let Err(e) = self.stream.shutdown(Shutdown::Read) { - eprintln!("Failed to shutdown socket: {}", e); - } - } -} - -impl Socket { - pub fn new(address: (Ipv4Addr, u16)) -> Result { - let stream = TcpStream::connect(address)?; - - Ok(Socket { - stream, - buffer: vec![0; 0x1000], - }) - } - - pub fn read(&mut self) -> Result<&[u8], Error> { - let read = self.stream.read(&mut self.buffer)?; - Ok(&self.buffer[..read]) - } -}