├── .DS_Store ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── interface.png ├── logo.png └── src ├── app.rs ├── main.rs └── ui.rs /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henryoman/dj-cli/5e86fa3a38eb6acd9590b177c4ef2e545703410d/.DS_Store -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | # Maintain dependencies for Cargo 9 | - package-ecosystem: "cargo" 10 | directory: "/" # Location of package manifests 11 | schedule: 12 | interval: "weekly" 13 | # Maintain dependencies for GitHub Actions 14 | - package-ecosystem: github-actions 15 | directory: "/" 16 | schedule: 17 | interval: weekly 18 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | - master 9 | - develop 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | 14 | # ensure that the workflow is only triggered once per PR, subsequent pushes to the PR will cancel 15 | # and restart the workflow. See https://docs.github.com/en/actions/using-jobs/using-concurrency 16 | concurrency: 17 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | fmt: 22 | name: fmt 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v5 27 | - name: Install Rust stable 28 | uses: dtolnay/rust-toolchain@stable 29 | with: 30 | components: rustfmt 31 | - name: check formatting 32 | run: cargo fmt -- --check 33 | - name: Cache Cargo dependencies 34 | uses: Swatinem/rust-cache@v2 35 | clippy: 36 | name: clippy 37 | runs-on: ubuntu-latest 38 | permissions: 39 | checks: write 40 | steps: 41 | - name: Checkout 42 | uses: actions/checkout@v5 43 | - name: Install Rust stable 44 | uses: dtolnay/rust-toolchain@stable 45 | with: 46 | components: clippy 47 | - name: Run clippy action 48 | uses: clechasseur/rs-clippy-check@v3 49 | - name: Cache Cargo dependencies 50 | uses: Swatinem/rust-cache@v2 51 | doc: 52 | # run docs generation on nightly rather than stable. This enables features like 53 | # https://doc.rust-lang.org/beta/unstable-book/language-features/doc-cfg.html which allows an 54 | # API be documented as only available in some specific platforms. 55 | name: doc 56 | runs-on: ubuntu-latest 57 | steps: 58 | - uses: actions/checkout@v5 59 | - name: Install Rust nightly 60 | uses: dtolnay/rust-toolchain@nightly 61 | - name: Run cargo doc 62 | run: cargo doc --no-deps --all-features 63 | env: 64 | RUSTDOCFLAGS: --cfg docsrs 65 | test: 66 | runs-on: ${{ matrix.os }} 67 | name: test ${{ matrix.os }} 68 | strategy: 69 | fail-fast: false 70 | matrix: 71 | os: [macos-latest, windows-latest] 72 | steps: 73 | # if your project needs OpenSSL, uncomment this to fix Windows builds. 74 | # it's commented out by default as the install command takes 5-10m. 75 | # - run: echo "VCPKG_ROOT=$env:VCPKG_INSTALLATION_ROOT" | Out-File -FilePath $env:GITHUB_ENV -Append 76 | # if: runner.os == 'Windows' 77 | # - run: vcpkg install openssl:x64-windows-static-md 78 | # if: runner.os == 'Windows' 79 | - uses: actions/checkout@v5 80 | - name: Install Rust 81 | uses: dtolnay/rust-toolchain@stable 82 | # enable this ci template to run regardless of whether the lockfile is checked in or not 83 | - name: cargo generate-lockfile 84 | if: hashFiles('Cargo.lock') == '' 85 | run: cargo generate-lockfile 86 | - name: cargo test --locked 87 | run: cargo test --locked --all-features --all-targets 88 | - name: Cache Cargo dependencies 89 | uses: Swatinem/rust-cache@v2 90 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | 3 | # macOS system files 4 | .DS_Store 5 | .DS_Store? 6 | ._* 7 | .Spotlight-V100 8 | .Trashes 9 | ehthumbs.db 10 | Thumbs.db 11 | 12 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "0.7.20" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "aho-corasick" 31 | version = "1.1.3" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 34 | dependencies = [ 35 | "memchr", 36 | ] 37 | 38 | [[package]] 39 | name = "allocator-api2" 40 | version = "0.2.21" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 43 | 44 | [[package]] 45 | name = "android-tzdata" 46 | version = "0.1.1" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 49 | 50 | [[package]] 51 | name = "android_system_properties" 52 | version = "0.1.5" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 55 | dependencies = [ 56 | "libc", 57 | ] 58 | 59 | [[package]] 60 | name = "ansi_term" 61 | version = "0.12.1" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 64 | dependencies = [ 65 | "winapi 0.3.9", 66 | ] 67 | 68 | [[package]] 69 | name = "async-broadcast" 70 | version = "0.7.2" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" 73 | dependencies = [ 74 | "event-listener", 75 | "event-listener-strategy", 76 | "futures-core", 77 | "pin-project-lite", 78 | ] 79 | 80 | [[package]] 81 | name = "async-channel" 82 | version = "2.5.0" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" 85 | dependencies = [ 86 | "concurrent-queue", 87 | "event-listener-strategy", 88 | "futures-core", 89 | "pin-project-lite", 90 | ] 91 | 92 | [[package]] 93 | name = "async-executor" 94 | version = "1.13.3" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" 97 | dependencies = [ 98 | "async-task", 99 | "concurrent-queue", 100 | "fastrand", 101 | "futures-lite", 102 | "pin-project-lite", 103 | "slab", 104 | ] 105 | 106 | [[package]] 107 | name = "async-io" 108 | version = "2.5.0" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" 111 | dependencies = [ 112 | "async-lock", 113 | "cfg-if 1.0.3", 114 | "concurrent-queue", 115 | "futures-io", 116 | "futures-lite", 117 | "parking", 118 | "polling", 119 | "rustix 1.0.8", 120 | "slab", 121 | "windows-sys 0.60.2", 122 | ] 123 | 124 | [[package]] 125 | name = "async-lock" 126 | version = "3.4.1" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" 129 | dependencies = [ 130 | "event-listener", 131 | "event-listener-strategy", 132 | "pin-project-lite", 133 | ] 134 | 135 | [[package]] 136 | name = "async-process" 137 | version = "2.4.0" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" 140 | dependencies = [ 141 | "async-channel", 142 | "async-io", 143 | "async-lock", 144 | "async-signal", 145 | "async-task", 146 | "blocking", 147 | "cfg-if 1.0.3", 148 | "event-listener", 149 | "futures-lite", 150 | "rustix 1.0.8", 151 | ] 152 | 153 | [[package]] 154 | name = "async-recursion" 155 | version = "1.1.1" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" 158 | dependencies = [ 159 | "proc-macro2", 160 | "quote", 161 | "syn 2.0.106", 162 | ] 163 | 164 | [[package]] 165 | name = "async-signal" 166 | version = "0.2.12" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" 169 | dependencies = [ 170 | "async-io", 171 | "async-lock", 172 | "atomic-waker", 173 | "cfg-if 1.0.3", 174 | "futures-core", 175 | "futures-io", 176 | "rustix 1.0.8", 177 | "signal-hook-registry", 178 | "slab", 179 | "windows-sys 0.60.2", 180 | ] 181 | 182 | [[package]] 183 | name = "async-task" 184 | version = "4.7.1" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" 187 | 188 | [[package]] 189 | name = "async-trait" 190 | version = "0.1.89" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" 193 | dependencies = [ 194 | "proc-macro2", 195 | "quote", 196 | "syn 2.0.106", 197 | ] 198 | 199 | [[package]] 200 | name = "atomic-waker" 201 | version = "1.1.2" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 204 | 205 | [[package]] 206 | name = "atty" 207 | version = "0.2.14" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 210 | dependencies = [ 211 | "hermit-abi 0.1.19", 212 | "libc", 213 | "winapi 0.3.9", 214 | ] 215 | 216 | [[package]] 217 | name = "autocfg" 218 | version = "1.5.0" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 221 | 222 | [[package]] 223 | name = "backtrace" 224 | version = "0.3.75" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" 227 | dependencies = [ 228 | "addr2line", 229 | "cfg-if 1.0.3", 230 | "libc", 231 | "miniz_oxide", 232 | "object", 233 | "rustc-demangle", 234 | "windows-targets 0.52.6", 235 | ] 236 | 237 | [[package]] 238 | name = "bitflags" 239 | version = "1.3.2" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 242 | 243 | [[package]] 244 | name = "bitflags" 245 | version = "2.9.3" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" 248 | 249 | [[package]] 250 | name = "block2" 251 | version = "0.6.1" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" 254 | dependencies = [ 255 | "objc2", 256 | ] 257 | 258 | [[package]] 259 | name = "blocking" 260 | version = "1.6.2" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" 263 | dependencies = [ 264 | "async-channel", 265 | "async-task", 266 | "futures-io", 267 | "futures-lite", 268 | "piper", 269 | ] 270 | 271 | [[package]] 272 | name = "bstr" 273 | version = "0.2.17" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" 276 | dependencies = [ 277 | "memchr", 278 | ] 279 | 280 | [[package]] 281 | name = "bumpalo" 282 | version = "3.19.0" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" 285 | 286 | [[package]] 287 | name = "byteorder" 288 | version = "1.5.0" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 291 | 292 | [[package]] 293 | name = "bytes" 294 | version = "1.10.1" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 297 | 298 | [[package]] 299 | name = "camino" 300 | version = "1.1.12" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" 303 | dependencies = [ 304 | "serde", 305 | ] 306 | 307 | [[package]] 308 | name = "cargo-platform" 309 | version = "0.1.9" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" 312 | dependencies = [ 313 | "serde", 314 | ] 315 | 316 | [[package]] 317 | name = "cargo-watch" 318 | version = "8.5.3" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "6fee2a949f4d075f1d2ff3bc49feba865145eae3367f331596ecb47477903a16" 321 | dependencies = [ 322 | "camino", 323 | "cargo_metadata", 324 | "clap", 325 | "dotenvy", 326 | "log", 327 | "notify-rust", 328 | "shell-escape", 329 | "stderrlog", 330 | "watchexec", 331 | ] 332 | 333 | [[package]] 334 | name = "cargo_metadata" 335 | version = "0.18.1" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" 338 | dependencies = [ 339 | "camino", 340 | "cargo-platform", 341 | "semver", 342 | "serde", 343 | "serde_json", 344 | "thiserror 1.0.69", 345 | ] 346 | 347 | [[package]] 348 | name = "cassowary" 349 | version = "0.3.0" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" 352 | 353 | [[package]] 354 | name = "castaway" 355 | version = "0.2.4" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" 358 | dependencies = [ 359 | "rustversion", 360 | ] 361 | 362 | [[package]] 363 | name = "cc" 364 | version = "1.2.34" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" 367 | dependencies = [ 368 | "shlex", 369 | ] 370 | 371 | [[package]] 372 | name = "cfg-if" 373 | version = "0.1.10" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 376 | 377 | [[package]] 378 | name = "cfg-if" 379 | version = "1.0.3" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" 382 | 383 | [[package]] 384 | name = "cfg_aliases" 385 | version = "0.2.1" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 388 | 389 | [[package]] 390 | name = "chrono" 391 | version = "0.4.41" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" 394 | dependencies = [ 395 | "android-tzdata", 396 | "iana-time-zone", 397 | "js-sys", 398 | "num-traits", 399 | "pure-rust-locales", 400 | "wasm-bindgen", 401 | "windows-link", 402 | ] 403 | 404 | [[package]] 405 | name = "clap" 406 | version = "2.34.0" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 409 | dependencies = [ 410 | "ansi_term", 411 | "atty", 412 | "bitflags 1.3.2", 413 | "strsim 0.8.0", 414 | "textwrap", 415 | "unicode-width 0.1.14", 416 | "vec_map", 417 | ] 418 | 419 | [[package]] 420 | name = "clearscreen" 421 | version = "1.0.11" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "e55dadbdd203f69c0a107bc78fca6e47d605345610ee77dcf24203fdf510b317" 424 | dependencies = [ 425 | "nix 0.24.3", 426 | "terminfo", 427 | "thiserror 1.0.69", 428 | "which 4.4.2", 429 | "winapi 0.3.9", 430 | ] 431 | 432 | [[package]] 433 | name = "color-eyre" 434 | version = "0.6.5" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" 437 | dependencies = [ 438 | "backtrace", 439 | "color-spantrace", 440 | "eyre", 441 | "indenter", 442 | "once_cell", 443 | "owo-colors", 444 | "tracing-error", 445 | ] 446 | 447 | [[package]] 448 | name = "color-spantrace" 449 | version = "0.3.0" 450 | source = "registry+https://github.com/rust-lang/crates.io-index" 451 | checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" 452 | dependencies = [ 453 | "once_cell", 454 | "owo-colors", 455 | "tracing-core", 456 | "tracing-error", 457 | ] 458 | 459 | [[package]] 460 | name = "command-group" 461 | version = "1.0.8" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "f7a8a86f409b4a59df3a3e4bee2de0b83f1755fdd2a25e3a9684c396fc4bed2c" 464 | dependencies = [ 465 | "nix 0.22.3", 466 | "winapi 0.3.9", 467 | ] 468 | 469 | [[package]] 470 | name = "compact_str" 471 | version = "0.8.1" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" 474 | dependencies = [ 475 | "castaway", 476 | "cfg-if 1.0.3", 477 | "itoa", 478 | "rustversion", 479 | "ryu", 480 | "static_assertions", 481 | ] 482 | 483 | [[package]] 484 | name = "concurrent-queue" 485 | version = "2.5.0" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 488 | dependencies = [ 489 | "crossbeam-utils", 490 | ] 491 | 492 | [[package]] 493 | name = "convert_case" 494 | version = "0.7.1" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" 497 | dependencies = [ 498 | "unicode-segmentation", 499 | ] 500 | 501 | [[package]] 502 | name = "core-foundation-sys" 503 | version = "0.8.7" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 506 | 507 | [[package]] 508 | name = "crossbeam-utils" 509 | version = "0.8.21" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 512 | 513 | [[package]] 514 | name = "crossterm" 515 | version = "0.28.1" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" 518 | dependencies = [ 519 | "bitflags 2.9.3", 520 | "crossterm_winapi", 521 | "mio 1.0.4", 522 | "parking_lot", 523 | "rustix 0.38.44", 524 | "signal-hook", 525 | "signal-hook-mio", 526 | "winapi 0.3.9", 527 | ] 528 | 529 | [[package]] 530 | name = "crossterm" 531 | version = "0.29.0" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" 534 | dependencies = [ 535 | "bitflags 2.9.3", 536 | "crossterm_winapi", 537 | "derive_more", 538 | "document-features", 539 | "futures-core", 540 | "mio 1.0.4", 541 | "parking_lot", 542 | "rustix 1.0.8", 543 | "signal-hook", 544 | "signal-hook-mio", 545 | "winapi 0.3.9", 546 | ] 547 | 548 | [[package]] 549 | name = "crossterm_winapi" 550 | version = "0.9.1" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 553 | dependencies = [ 554 | "winapi 0.3.9", 555 | ] 556 | 557 | [[package]] 558 | name = "darling" 559 | version = "0.12.4" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c" 562 | dependencies = [ 563 | "darling_core 0.12.4", 564 | "darling_macro 0.12.4", 565 | ] 566 | 567 | [[package]] 568 | name = "darling" 569 | version = "0.20.11" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" 572 | dependencies = [ 573 | "darling_core 0.20.11", 574 | "darling_macro 0.20.11", 575 | ] 576 | 577 | [[package]] 578 | name = "darling_core" 579 | version = "0.12.4" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36" 582 | dependencies = [ 583 | "fnv", 584 | "ident_case", 585 | "proc-macro2", 586 | "quote", 587 | "strsim 0.10.0", 588 | "syn 1.0.109", 589 | ] 590 | 591 | [[package]] 592 | name = "darling_core" 593 | version = "0.20.11" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" 596 | dependencies = [ 597 | "fnv", 598 | "ident_case", 599 | "proc-macro2", 600 | "quote", 601 | "strsim 0.11.1", 602 | "syn 2.0.106", 603 | ] 604 | 605 | [[package]] 606 | name = "darling_macro" 607 | version = "0.12.4" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a" 610 | dependencies = [ 611 | "darling_core 0.12.4", 612 | "quote", 613 | "syn 1.0.109", 614 | ] 615 | 616 | [[package]] 617 | name = "darling_macro" 618 | version = "0.20.11" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" 621 | dependencies = [ 622 | "darling_core 0.20.11", 623 | "quote", 624 | "syn 2.0.106", 625 | ] 626 | 627 | [[package]] 628 | name = "deranged" 629 | version = "0.4.0" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" 632 | dependencies = [ 633 | "powerfmt", 634 | ] 635 | 636 | [[package]] 637 | name = "derive_builder" 638 | version = "0.10.2" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "d13202debe11181040ae9063d739fa32cfcaaebe2275fe387703460ae2365b30" 641 | dependencies = [ 642 | "derive_builder_macro", 643 | ] 644 | 645 | [[package]] 646 | name = "derive_builder_core" 647 | version = "0.10.2" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5" 650 | dependencies = [ 651 | "darling 0.12.4", 652 | "proc-macro2", 653 | "quote", 654 | "syn 1.0.109", 655 | ] 656 | 657 | [[package]] 658 | name = "derive_builder_macro" 659 | version = "0.10.2" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "58a94ace95092c5acb1e97a7e846b310cfbd499652f72297da7493f618a98d73" 662 | dependencies = [ 663 | "derive_builder_core", 664 | "syn 1.0.109", 665 | ] 666 | 667 | [[package]] 668 | name = "derive_more" 669 | version = "2.0.1" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" 672 | dependencies = [ 673 | "derive_more-impl", 674 | ] 675 | 676 | [[package]] 677 | name = "derive_more-impl" 678 | version = "2.0.1" 679 | source = "registry+https://github.com/rust-lang/crates.io-index" 680 | checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" 681 | dependencies = [ 682 | "convert_case", 683 | "proc-macro2", 684 | "quote", 685 | "syn 2.0.106", 686 | ] 687 | 688 | [[package]] 689 | name = "dirs" 690 | version = "4.0.0" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" 693 | dependencies = [ 694 | "dirs-sys", 695 | ] 696 | 697 | [[package]] 698 | name = "dirs-sys" 699 | version = "0.3.7" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" 702 | dependencies = [ 703 | "libc", 704 | "redox_users", 705 | "winapi 0.3.9", 706 | ] 707 | 708 | [[package]] 709 | name = "dispatch2" 710 | version = "0.3.0" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" 713 | dependencies = [ 714 | "bitflags 2.9.3", 715 | "objc2", 716 | ] 717 | 718 | [[package]] 719 | name = "dj-cli" 720 | version = "0.1.0" 721 | dependencies = [ 722 | "cargo-watch", 723 | "color-eyre", 724 | "crossterm 0.29.0", 725 | "futures", 726 | "rat-text", 727 | "ratatui", 728 | "regex", 729 | "tokio", 730 | "tracing", 731 | "tracing-subscriber", 732 | "which 8.0.0", 733 | ] 734 | 735 | [[package]] 736 | name = "document-features" 737 | version = "0.2.11" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" 740 | dependencies = [ 741 | "litrs", 742 | ] 743 | 744 | [[package]] 745 | name = "dotenvy" 746 | version = "0.15.7" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 749 | 750 | [[package]] 751 | name = "dyn-clone" 752 | version = "1.0.20" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" 755 | 756 | [[package]] 757 | name = "either" 758 | version = "1.15.0" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 761 | 762 | [[package]] 763 | name = "endi" 764 | version = "1.1.0" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" 767 | 768 | [[package]] 769 | name = "enumflags2" 770 | version = "0.7.12" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" 773 | dependencies = [ 774 | "enumflags2_derive", 775 | "serde", 776 | ] 777 | 778 | [[package]] 779 | name = "enumflags2_derive" 780 | version = "0.7.12" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" 783 | dependencies = [ 784 | "proc-macro2", 785 | "quote", 786 | "syn 2.0.106", 787 | ] 788 | 789 | [[package]] 790 | name = "env_home" 791 | version = "0.1.0" 792 | source = "registry+https://github.com/rust-lang/crates.io-index" 793 | checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" 794 | 795 | [[package]] 796 | name = "equivalent" 797 | version = "1.0.2" 798 | source = "registry+https://github.com/rust-lang/crates.io-index" 799 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 800 | 801 | [[package]] 802 | name = "errno" 803 | version = "0.3.13" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" 806 | dependencies = [ 807 | "libc", 808 | "windows-sys 0.60.2", 809 | ] 810 | 811 | [[package]] 812 | name = "event-listener" 813 | version = "5.4.1" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" 816 | dependencies = [ 817 | "concurrent-queue", 818 | "parking", 819 | "pin-project-lite", 820 | ] 821 | 822 | [[package]] 823 | name = "event-listener-strategy" 824 | version = "0.5.4" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" 827 | dependencies = [ 828 | "event-listener", 829 | "pin-project-lite", 830 | ] 831 | 832 | [[package]] 833 | name = "eyre" 834 | version = "0.6.12" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" 837 | dependencies = [ 838 | "indenter", 839 | "once_cell", 840 | ] 841 | 842 | [[package]] 843 | name = "fastrand" 844 | version = "2.3.0" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 847 | 848 | [[package]] 849 | name = "filetime" 850 | version = "0.2.26" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" 853 | dependencies = [ 854 | "cfg-if 1.0.3", 855 | "libc", 856 | "libredox", 857 | "windows-sys 0.60.2", 858 | ] 859 | 860 | [[package]] 861 | name = "fnv" 862 | version = "1.0.7" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 865 | 866 | [[package]] 867 | name = "foldhash" 868 | version = "0.1.5" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" 871 | 872 | [[package]] 873 | name = "format_num_pattern" 874 | version = "0.9.3" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "39657b084f99a6df45351bac3df5f764acc57e7191f90efd6acd51e3256070a6" 877 | dependencies = [ 878 | "log", 879 | "memchr", 880 | "pure-rust-locales", 881 | ] 882 | 883 | [[package]] 884 | name = "fsevent" 885 | version = "0.4.0" 886 | source = "registry+https://github.com/rust-lang/crates.io-index" 887 | checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" 888 | dependencies = [ 889 | "bitflags 1.3.2", 890 | "fsevent-sys", 891 | ] 892 | 893 | [[package]] 894 | name = "fsevent-sys" 895 | version = "2.0.1" 896 | source = "registry+https://github.com/rust-lang/crates.io-index" 897 | checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" 898 | dependencies = [ 899 | "libc", 900 | ] 901 | 902 | [[package]] 903 | name = "fuchsia-zircon" 904 | version = "0.3.3" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 907 | dependencies = [ 908 | "bitflags 1.3.2", 909 | "fuchsia-zircon-sys", 910 | ] 911 | 912 | [[package]] 913 | name = "fuchsia-zircon-sys" 914 | version = "0.3.3" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 917 | 918 | [[package]] 919 | name = "futures" 920 | version = "0.3.31" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 923 | dependencies = [ 924 | "futures-channel", 925 | "futures-core", 926 | "futures-executor", 927 | "futures-io", 928 | "futures-sink", 929 | "futures-task", 930 | "futures-util", 931 | ] 932 | 933 | [[package]] 934 | name = "futures-channel" 935 | version = "0.3.31" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 938 | dependencies = [ 939 | "futures-core", 940 | "futures-sink", 941 | ] 942 | 943 | [[package]] 944 | name = "futures-core" 945 | version = "0.3.31" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 948 | 949 | [[package]] 950 | name = "futures-executor" 951 | version = "0.3.31" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 954 | dependencies = [ 955 | "futures-core", 956 | "futures-task", 957 | "futures-util", 958 | ] 959 | 960 | [[package]] 961 | name = "futures-io" 962 | version = "0.3.31" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 965 | 966 | [[package]] 967 | name = "futures-lite" 968 | version = "2.6.1" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" 971 | dependencies = [ 972 | "fastrand", 973 | "futures-core", 974 | "futures-io", 975 | "parking", 976 | "pin-project-lite", 977 | ] 978 | 979 | [[package]] 980 | name = "futures-macro" 981 | version = "0.3.31" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 984 | dependencies = [ 985 | "proc-macro2", 986 | "quote", 987 | "syn 2.0.106", 988 | ] 989 | 990 | [[package]] 991 | name = "futures-sink" 992 | version = "0.3.31" 993 | source = "registry+https://github.com/rust-lang/crates.io-index" 994 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 995 | 996 | [[package]] 997 | name = "futures-task" 998 | version = "0.3.31" 999 | source = "registry+https://github.com/rust-lang/crates.io-index" 1000 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 1001 | 1002 | [[package]] 1003 | name = "futures-util" 1004 | version = "0.3.31" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 1007 | dependencies = [ 1008 | "futures-channel", 1009 | "futures-core", 1010 | "futures-io", 1011 | "futures-macro", 1012 | "futures-sink", 1013 | "futures-task", 1014 | "memchr", 1015 | "pin-project-lite", 1016 | "pin-utils", 1017 | "slab", 1018 | ] 1019 | 1020 | [[package]] 1021 | name = "fxhash" 1022 | version = "0.2.1" 1023 | source = "registry+https://github.com/rust-lang/crates.io-index" 1024 | checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" 1025 | dependencies = [ 1026 | "byteorder", 1027 | ] 1028 | 1029 | [[package]] 1030 | name = "getrandom" 1031 | version = "0.2.16" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 1034 | dependencies = [ 1035 | "cfg-if 1.0.3", 1036 | "libc", 1037 | "wasi 0.11.1+wasi-snapshot-preview1", 1038 | ] 1039 | 1040 | [[package]] 1041 | name = "getrandom" 1042 | version = "0.3.3" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 1045 | dependencies = [ 1046 | "cfg-if 1.0.3", 1047 | "libc", 1048 | "r-efi", 1049 | "wasi 0.14.3+wasi-0.2.4", 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "gimli" 1054 | version = "0.31.1" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 1057 | 1058 | [[package]] 1059 | name = "glob" 1060 | version = "0.3.3" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" 1063 | 1064 | [[package]] 1065 | name = "globset" 1066 | version = "0.4.6" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" 1069 | dependencies = [ 1070 | "aho-corasick 0.7.20", 1071 | "bstr", 1072 | "fnv", 1073 | "log", 1074 | "regex", 1075 | ] 1076 | 1077 | [[package]] 1078 | name = "hashbrown" 1079 | version = "0.15.5" 1080 | source = "registry+https://github.com/rust-lang/crates.io-index" 1081 | checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 1082 | dependencies = [ 1083 | "allocator-api2", 1084 | "equivalent", 1085 | "foldhash", 1086 | ] 1087 | 1088 | [[package]] 1089 | name = "heck" 1090 | version = "0.5.0" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 1093 | 1094 | [[package]] 1095 | name = "hermit-abi" 1096 | version = "0.1.19" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 1099 | dependencies = [ 1100 | "libc", 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "hermit-abi" 1105 | version = "0.5.2" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" 1108 | 1109 | [[package]] 1110 | name = "hex" 1111 | version = "0.4.3" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 1114 | 1115 | [[package]] 1116 | name = "home" 1117 | version = "0.5.11" 1118 | source = "registry+https://github.com/rust-lang/crates.io-index" 1119 | checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" 1120 | dependencies = [ 1121 | "windows-sys 0.59.0", 1122 | ] 1123 | 1124 | [[package]] 1125 | name = "iana-time-zone" 1126 | version = "0.1.63" 1127 | source = "registry+https://github.com/rust-lang/crates.io-index" 1128 | checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" 1129 | dependencies = [ 1130 | "android_system_properties", 1131 | "core-foundation-sys", 1132 | "iana-time-zone-haiku", 1133 | "js-sys", 1134 | "log", 1135 | "wasm-bindgen", 1136 | "windows-core", 1137 | ] 1138 | 1139 | [[package]] 1140 | name = "iana-time-zone-haiku" 1141 | version = "0.1.2" 1142 | source = "registry+https://github.com/rust-lang/crates.io-index" 1143 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 1144 | dependencies = [ 1145 | "cc", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "ident_case" 1150 | version = "1.0.1" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 1153 | 1154 | [[package]] 1155 | name = "indenter" 1156 | version = "0.3.4" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" 1159 | 1160 | [[package]] 1161 | name = "indexmap" 1162 | version = "2.11.0" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" 1165 | dependencies = [ 1166 | "equivalent", 1167 | "hashbrown", 1168 | ] 1169 | 1170 | [[package]] 1171 | name = "indoc" 1172 | version = "2.0.6" 1173 | source = "registry+https://github.com/rust-lang/crates.io-index" 1174 | checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" 1175 | 1176 | [[package]] 1177 | name = "inotify" 1178 | version = "0.7.1" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" 1181 | dependencies = [ 1182 | "bitflags 1.3.2", 1183 | "inotify-sys", 1184 | "libc", 1185 | ] 1186 | 1187 | [[package]] 1188 | name = "inotify-sys" 1189 | version = "0.1.5" 1190 | source = "registry+https://github.com/rust-lang/crates.io-index" 1191 | checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" 1192 | dependencies = [ 1193 | "libc", 1194 | ] 1195 | 1196 | [[package]] 1197 | name = "instability" 1198 | version = "0.3.9" 1199 | source = "registry+https://github.com/rust-lang/crates.io-index" 1200 | checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a" 1201 | dependencies = [ 1202 | "darling 0.20.11", 1203 | "indoc", 1204 | "proc-macro2", 1205 | "quote", 1206 | "syn 2.0.106", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "io-uring" 1211 | version = "0.7.10" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" 1214 | dependencies = [ 1215 | "bitflags 2.9.3", 1216 | "cfg-if 1.0.3", 1217 | "libc", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "iovec" 1222 | version = "0.1.4" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 1225 | dependencies = [ 1226 | "libc", 1227 | ] 1228 | 1229 | [[package]] 1230 | name = "is-terminal" 1231 | version = "0.4.16" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" 1234 | dependencies = [ 1235 | "hermit-abi 0.5.2", 1236 | "libc", 1237 | "windows-sys 0.59.0", 1238 | ] 1239 | 1240 | [[package]] 1241 | name = "iset" 1242 | version = "0.3.1" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | checksum = "855de4169757ca6b92b396d7a0380ef234e9a1ec2ec603c80779453ed0ab45e4" 1245 | 1246 | [[package]] 1247 | name = "itertools" 1248 | version = "0.13.0" 1249 | source = "registry+https://github.com/rust-lang/crates.io-index" 1250 | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 1251 | dependencies = [ 1252 | "either", 1253 | ] 1254 | 1255 | [[package]] 1256 | name = "itoa" 1257 | version = "1.0.15" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 1260 | 1261 | [[package]] 1262 | name = "js-sys" 1263 | version = "0.3.77" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 1266 | dependencies = [ 1267 | "once_cell", 1268 | "wasm-bindgen", 1269 | ] 1270 | 1271 | [[package]] 1272 | name = "kernel32-sys" 1273 | version = "0.2.2" 1274 | source = "registry+https://github.com/rust-lang/crates.io-index" 1275 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 1276 | dependencies = [ 1277 | "winapi 0.2.8", 1278 | "winapi-build", 1279 | ] 1280 | 1281 | [[package]] 1282 | name = "lazy_static" 1283 | version = "1.5.0" 1284 | source = "registry+https://github.com/rust-lang/crates.io-index" 1285 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 1286 | 1287 | [[package]] 1288 | name = "lazycell" 1289 | version = "1.3.0" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 1292 | 1293 | [[package]] 1294 | name = "libc" 1295 | version = "0.2.175" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" 1298 | 1299 | [[package]] 1300 | name = "libredox" 1301 | version = "0.1.9" 1302 | source = "registry+https://github.com/rust-lang/crates.io-index" 1303 | checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" 1304 | dependencies = [ 1305 | "bitflags 2.9.3", 1306 | "libc", 1307 | "redox_syscall", 1308 | ] 1309 | 1310 | [[package]] 1311 | name = "linux-raw-sys" 1312 | version = "0.4.15" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 1315 | 1316 | [[package]] 1317 | name = "linux-raw-sys" 1318 | version = "0.9.4" 1319 | source = "registry+https://github.com/rust-lang/crates.io-index" 1320 | checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" 1321 | 1322 | [[package]] 1323 | name = "litrs" 1324 | version = "0.4.2" 1325 | source = "registry+https://github.com/rust-lang/crates.io-index" 1326 | checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" 1327 | 1328 | [[package]] 1329 | name = "lock_api" 1330 | version = "0.4.13" 1331 | source = "registry+https://github.com/rust-lang/crates.io-index" 1332 | checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" 1333 | dependencies = [ 1334 | "autocfg", 1335 | "scopeguard", 1336 | ] 1337 | 1338 | [[package]] 1339 | name = "log" 1340 | version = "0.4.27" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 1343 | 1344 | [[package]] 1345 | name = "lru" 1346 | version = "0.12.5" 1347 | source = "registry+https://github.com/rust-lang/crates.io-index" 1348 | checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" 1349 | dependencies = [ 1350 | "hashbrown", 1351 | ] 1352 | 1353 | [[package]] 1354 | name = "mac-notification-sys" 1355 | version = "0.6.6" 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" 1357 | checksum = "119c8490084af61b44c9eda9d626475847a186737c0378c85e32d77c33a01cd4" 1358 | dependencies = [ 1359 | "cc", 1360 | "objc2", 1361 | "objc2-foundation", 1362 | "time", 1363 | ] 1364 | 1365 | [[package]] 1366 | name = "memchr" 1367 | version = "2.7.5" 1368 | source = "registry+https://github.com/rust-lang/crates.io-index" 1369 | checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" 1370 | 1371 | [[package]] 1372 | name = "memoffset" 1373 | version = "0.6.5" 1374 | source = "registry+https://github.com/rust-lang/crates.io-index" 1375 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 1376 | dependencies = [ 1377 | "autocfg", 1378 | ] 1379 | 1380 | [[package]] 1381 | name = "memoffset" 1382 | version = "0.9.1" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" 1385 | dependencies = [ 1386 | "autocfg", 1387 | ] 1388 | 1389 | [[package]] 1390 | name = "miniz_oxide" 1391 | version = "0.8.9" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" 1394 | dependencies = [ 1395 | "adler2", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "mio" 1400 | version = "0.6.23" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" 1403 | dependencies = [ 1404 | "cfg-if 0.1.10", 1405 | "fuchsia-zircon", 1406 | "fuchsia-zircon-sys", 1407 | "iovec", 1408 | "kernel32-sys", 1409 | "libc", 1410 | "log", 1411 | "miow", 1412 | "net2", 1413 | "slab", 1414 | "winapi 0.2.8", 1415 | ] 1416 | 1417 | [[package]] 1418 | name = "mio" 1419 | version = "1.0.4" 1420 | source = "registry+https://github.com/rust-lang/crates.io-index" 1421 | checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" 1422 | dependencies = [ 1423 | "libc", 1424 | "log", 1425 | "wasi 0.11.1+wasi-snapshot-preview1", 1426 | "windows-sys 0.59.0", 1427 | ] 1428 | 1429 | [[package]] 1430 | name = "mio-extras" 1431 | version = "2.0.6" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" 1434 | dependencies = [ 1435 | "lazycell", 1436 | "log", 1437 | "mio 0.6.23", 1438 | "slab", 1439 | ] 1440 | 1441 | [[package]] 1442 | name = "miow" 1443 | version = "0.2.2" 1444 | source = "registry+https://github.com/rust-lang/crates.io-index" 1445 | checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" 1446 | dependencies = [ 1447 | "kernel32-sys", 1448 | "net2", 1449 | "winapi 0.2.8", 1450 | "ws2_32-sys", 1451 | ] 1452 | 1453 | [[package]] 1454 | name = "net2" 1455 | version = "0.2.39" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" 1458 | dependencies = [ 1459 | "cfg-if 0.1.10", 1460 | "libc", 1461 | "winapi 0.3.9", 1462 | ] 1463 | 1464 | [[package]] 1465 | name = "nix" 1466 | version = "0.22.3" 1467 | source = "registry+https://github.com/rust-lang/crates.io-index" 1468 | checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" 1469 | dependencies = [ 1470 | "bitflags 1.3.2", 1471 | "cc", 1472 | "cfg-if 1.0.3", 1473 | "libc", 1474 | "memoffset 0.6.5", 1475 | ] 1476 | 1477 | [[package]] 1478 | name = "nix" 1479 | version = "0.24.3" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" 1482 | dependencies = [ 1483 | "bitflags 1.3.2", 1484 | "cfg-if 1.0.3", 1485 | "libc", 1486 | ] 1487 | 1488 | [[package]] 1489 | name = "nix" 1490 | version = "0.30.1" 1491 | source = "registry+https://github.com/rust-lang/crates.io-index" 1492 | checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" 1493 | dependencies = [ 1494 | "bitflags 2.9.3", 1495 | "cfg-if 1.0.3", 1496 | "cfg_aliases", 1497 | "libc", 1498 | "memoffset 0.9.1", 1499 | ] 1500 | 1501 | [[package]] 1502 | name = "nom" 1503 | version = "5.1.3" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b" 1506 | dependencies = [ 1507 | "memchr", 1508 | "version_check", 1509 | ] 1510 | 1511 | [[package]] 1512 | name = "notify" 1513 | version = "4.0.18" 1514 | source = "registry+https://github.com/rust-lang/crates.io-index" 1515 | checksum = "b72dd35279a5dc895a30965e247b0961ba36c233dc48454a2de8ccd459f1afd3" 1516 | dependencies = [ 1517 | "bitflags 1.3.2", 1518 | "filetime", 1519 | "fsevent", 1520 | "fsevent-sys", 1521 | "inotify", 1522 | "libc", 1523 | "mio 0.6.23", 1524 | "mio-extras", 1525 | "walkdir", 1526 | "winapi 0.3.9", 1527 | ] 1528 | 1529 | [[package]] 1530 | name = "notify-rust" 1531 | version = "4.11.7" 1532 | source = "registry+https://github.com/rust-lang/crates.io-index" 1533 | checksum = "6442248665a5aa2514e794af3b39661a8e73033b1cc5e59899e1276117ee4400" 1534 | dependencies = [ 1535 | "futures-lite", 1536 | "log", 1537 | "mac-notification-sys", 1538 | "serde", 1539 | "tauri-winrt-notification", 1540 | "zbus", 1541 | ] 1542 | 1543 | [[package]] 1544 | name = "nu-ansi-term" 1545 | version = "0.50.1" 1546 | source = "registry+https://github.com/rust-lang/crates.io-index" 1547 | checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" 1548 | dependencies = [ 1549 | "windows-sys 0.52.0", 1550 | ] 1551 | 1552 | [[package]] 1553 | name = "num-conv" 1554 | version = "0.1.0" 1555 | source = "registry+https://github.com/rust-lang/crates.io-index" 1556 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1557 | 1558 | [[package]] 1559 | name = "num-traits" 1560 | version = "0.2.19" 1561 | source = "registry+https://github.com/rust-lang/crates.io-index" 1562 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1563 | dependencies = [ 1564 | "autocfg", 1565 | ] 1566 | 1567 | [[package]] 1568 | name = "objc2" 1569 | version = "0.6.2" 1570 | source = "registry+https://github.com/rust-lang/crates.io-index" 1571 | checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc" 1572 | dependencies = [ 1573 | "objc2-encode", 1574 | ] 1575 | 1576 | [[package]] 1577 | name = "objc2-core-foundation" 1578 | version = "0.3.1" 1579 | source = "registry+https://github.com/rust-lang/crates.io-index" 1580 | checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" 1581 | dependencies = [ 1582 | "bitflags 2.9.3", 1583 | "dispatch2", 1584 | "objc2", 1585 | ] 1586 | 1587 | [[package]] 1588 | name = "objc2-encode" 1589 | version = "4.1.0" 1590 | source = "registry+https://github.com/rust-lang/crates.io-index" 1591 | checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" 1592 | 1593 | [[package]] 1594 | name = "objc2-foundation" 1595 | version = "0.3.1" 1596 | source = "registry+https://github.com/rust-lang/crates.io-index" 1597 | checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" 1598 | dependencies = [ 1599 | "bitflags 2.9.3", 1600 | "block2", 1601 | "libc", 1602 | "objc2", 1603 | "objc2-core-foundation", 1604 | ] 1605 | 1606 | [[package]] 1607 | name = "object" 1608 | version = "0.36.7" 1609 | source = "registry+https://github.com/rust-lang/crates.io-index" 1610 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 1611 | dependencies = [ 1612 | "memchr", 1613 | ] 1614 | 1615 | [[package]] 1616 | name = "once_cell" 1617 | version = "1.21.3" 1618 | source = "registry+https://github.com/rust-lang/crates.io-index" 1619 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 1620 | 1621 | [[package]] 1622 | name = "ordered-stream" 1623 | version = "0.2.0" 1624 | source = "registry+https://github.com/rust-lang/crates.io-index" 1625 | checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" 1626 | dependencies = [ 1627 | "futures-core", 1628 | "pin-project-lite", 1629 | ] 1630 | 1631 | [[package]] 1632 | name = "owo-colors" 1633 | version = "4.2.2" 1634 | source = "registry+https://github.com/rust-lang/crates.io-index" 1635 | checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e" 1636 | 1637 | [[package]] 1638 | name = "parking" 1639 | version = "2.2.1" 1640 | source = "registry+https://github.com/rust-lang/crates.io-index" 1641 | checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 1642 | 1643 | [[package]] 1644 | name = "parking_lot" 1645 | version = "0.12.4" 1646 | source = "registry+https://github.com/rust-lang/crates.io-index" 1647 | checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" 1648 | dependencies = [ 1649 | "lock_api", 1650 | "parking_lot_core", 1651 | ] 1652 | 1653 | [[package]] 1654 | name = "parking_lot_core" 1655 | version = "0.9.11" 1656 | source = "registry+https://github.com/rust-lang/crates.io-index" 1657 | checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" 1658 | dependencies = [ 1659 | "cfg-if 1.0.3", 1660 | "libc", 1661 | "redox_syscall", 1662 | "smallvec", 1663 | "windows-targets 0.52.6", 1664 | ] 1665 | 1666 | [[package]] 1667 | name = "paste" 1668 | version = "1.0.15" 1669 | source = "registry+https://github.com/rust-lang/crates.io-index" 1670 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1671 | 1672 | [[package]] 1673 | name = "phf" 1674 | version = "0.11.3" 1675 | source = "registry+https://github.com/rust-lang/crates.io-index" 1676 | checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" 1677 | dependencies = [ 1678 | "phf_shared", 1679 | ] 1680 | 1681 | [[package]] 1682 | name = "phf_codegen" 1683 | version = "0.11.3" 1684 | source = "registry+https://github.com/rust-lang/crates.io-index" 1685 | checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" 1686 | dependencies = [ 1687 | "phf_generator", 1688 | "phf_shared", 1689 | ] 1690 | 1691 | [[package]] 1692 | name = "phf_generator" 1693 | version = "0.11.3" 1694 | source = "registry+https://github.com/rust-lang/crates.io-index" 1695 | checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" 1696 | dependencies = [ 1697 | "phf_shared", 1698 | "rand", 1699 | ] 1700 | 1701 | [[package]] 1702 | name = "phf_shared" 1703 | version = "0.11.3" 1704 | source = "registry+https://github.com/rust-lang/crates.io-index" 1705 | checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" 1706 | dependencies = [ 1707 | "siphasher", 1708 | ] 1709 | 1710 | [[package]] 1711 | name = "pin-project-lite" 1712 | version = "0.2.16" 1713 | source = "registry+https://github.com/rust-lang/crates.io-index" 1714 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1715 | 1716 | [[package]] 1717 | name = "pin-utils" 1718 | version = "0.1.0" 1719 | source = "registry+https://github.com/rust-lang/crates.io-index" 1720 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1721 | 1722 | [[package]] 1723 | name = "piper" 1724 | version = "0.2.4" 1725 | source = "registry+https://github.com/rust-lang/crates.io-index" 1726 | checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" 1727 | dependencies = [ 1728 | "atomic-waker", 1729 | "fastrand", 1730 | "futures-io", 1731 | ] 1732 | 1733 | [[package]] 1734 | name = "polling" 1735 | version = "3.10.0" 1736 | source = "registry+https://github.com/rust-lang/crates.io-index" 1737 | checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" 1738 | dependencies = [ 1739 | "cfg-if 1.0.3", 1740 | "concurrent-queue", 1741 | "hermit-abi 0.5.2", 1742 | "pin-project-lite", 1743 | "rustix 1.0.8", 1744 | "windows-sys 0.60.2", 1745 | ] 1746 | 1747 | [[package]] 1748 | name = "powerfmt" 1749 | version = "0.2.0" 1750 | source = "registry+https://github.com/rust-lang/crates.io-index" 1751 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1752 | 1753 | [[package]] 1754 | name = "proc-macro-crate" 1755 | version = "3.3.0" 1756 | source = "registry+https://github.com/rust-lang/crates.io-index" 1757 | checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" 1758 | dependencies = [ 1759 | "toml_edit", 1760 | ] 1761 | 1762 | [[package]] 1763 | name = "proc-macro2" 1764 | version = "1.0.101" 1765 | source = "registry+https://github.com/rust-lang/crates.io-index" 1766 | checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" 1767 | dependencies = [ 1768 | "unicode-ident", 1769 | ] 1770 | 1771 | [[package]] 1772 | name = "pure-rust-locales" 1773 | version = "0.8.1" 1774 | source = "registry+https://github.com/rust-lang/crates.io-index" 1775 | checksum = "1190fd18ae6ce9e137184f207593877e70f39b015040156b1e05081cdfe3733a" 1776 | 1777 | [[package]] 1778 | name = "quick-xml" 1779 | version = "0.37.5" 1780 | source = "registry+https://github.com/rust-lang/crates.io-index" 1781 | checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" 1782 | dependencies = [ 1783 | "memchr", 1784 | ] 1785 | 1786 | [[package]] 1787 | name = "quote" 1788 | version = "1.0.40" 1789 | source = "registry+https://github.com/rust-lang/crates.io-index" 1790 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 1791 | dependencies = [ 1792 | "proc-macro2", 1793 | ] 1794 | 1795 | [[package]] 1796 | name = "r-efi" 1797 | version = "5.3.0" 1798 | source = "registry+https://github.com/rust-lang/crates.io-index" 1799 | checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 1800 | 1801 | [[package]] 1802 | name = "rand" 1803 | version = "0.8.5" 1804 | source = "registry+https://github.com/rust-lang/crates.io-index" 1805 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1806 | dependencies = [ 1807 | "rand_core", 1808 | ] 1809 | 1810 | [[package]] 1811 | name = "rand_core" 1812 | version = "0.6.4" 1813 | source = "registry+https://github.com/rust-lang/crates.io-index" 1814 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1815 | 1816 | [[package]] 1817 | name = "rat-cursor" 1818 | version = "1.2.0" 1819 | source = "registry+https://github.com/rust-lang/crates.io-index" 1820 | checksum = "37427a103efff37496fad20528e767ba658737e731dff1cf9231104859455dc0" 1821 | 1822 | [[package]] 1823 | name = "rat-event" 1824 | version = "1.2.3" 1825 | source = "registry+https://github.com/rust-lang/crates.io-index" 1826 | checksum = "26e333b72bcd23f28ac85ba6441c5e75600ace55947e71930e7cb327e6716286" 1827 | dependencies = [ 1828 | "crossterm 0.28.1", 1829 | "log", 1830 | "ratatui", 1831 | ] 1832 | 1833 | [[package]] 1834 | name = "rat-focus" 1835 | version = "1.0.2" 1836 | source = "registry+https://github.com/rust-lang/crates.io-index" 1837 | checksum = "1b4866c2abcc7b8c8744548b4849c67b654d2dd28ee118fcc9b65979c96247cb" 1838 | dependencies = [ 1839 | "crossterm 0.28.1", 1840 | "fxhash", 1841 | "log", 1842 | "rat-event", 1843 | "rat-reloc", 1844 | "ratatui", 1845 | ] 1846 | 1847 | [[package]] 1848 | name = "rat-reloc" 1849 | version = "1.1.2" 1850 | source = "registry+https://github.com/rust-lang/crates.io-index" 1851 | checksum = "fbddcf2d92aae0efb227180c07d8fbbb4480cd30318e4e6f5825aae8f6dc5ba5" 1852 | dependencies = [ 1853 | "log", 1854 | "ratatui", 1855 | ] 1856 | 1857 | [[package]] 1858 | name = "rat-scrolled" 1859 | version = "1.1.2" 1860 | source = "registry+https://github.com/rust-lang/crates.io-index" 1861 | checksum = "0bef575500e9a54d649a470abf1ec136929845bfced1badb5fda4994c6ce39f9" 1862 | dependencies = [ 1863 | "crossterm 0.28.1", 1864 | "log", 1865 | "rat-event", 1866 | "rat-reloc", 1867 | "ratatui", 1868 | ] 1869 | 1870 | [[package]] 1871 | name = "rat-text" 1872 | version = "1.0.5" 1873 | source = "registry+https://github.com/rust-lang/crates.io-index" 1874 | checksum = "95641a2429aeb420a2c37d7a8c0395cf28ce4ac4f32d914813196ca22a7a3004" 1875 | dependencies = [ 1876 | "chrono", 1877 | "crossterm 0.28.1", 1878 | "dyn-clone", 1879 | "format_num_pattern", 1880 | "iset", 1881 | "log", 1882 | "pure-rust-locales", 1883 | "rat-cursor", 1884 | "rat-event", 1885 | "rat-focus", 1886 | "rat-reloc", 1887 | "rat-scrolled", 1888 | "ratatui", 1889 | "ropey", 1890 | "unicode-display-width", 1891 | "unicode-segmentation", 1892 | ] 1893 | 1894 | [[package]] 1895 | name = "ratatui" 1896 | version = "0.29.0" 1897 | source = "registry+https://github.com/rust-lang/crates.io-index" 1898 | checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" 1899 | dependencies = [ 1900 | "bitflags 2.9.3", 1901 | "cassowary", 1902 | "compact_str", 1903 | "crossterm 0.28.1", 1904 | "indoc", 1905 | "instability", 1906 | "itertools", 1907 | "lru", 1908 | "paste", 1909 | "strum", 1910 | "unicode-segmentation", 1911 | "unicode-truncate", 1912 | "unicode-width 0.2.0", 1913 | ] 1914 | 1915 | [[package]] 1916 | name = "redox_syscall" 1917 | version = "0.5.17" 1918 | source = "registry+https://github.com/rust-lang/crates.io-index" 1919 | checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" 1920 | dependencies = [ 1921 | "bitflags 2.9.3", 1922 | ] 1923 | 1924 | [[package]] 1925 | name = "redox_users" 1926 | version = "0.4.6" 1927 | source = "registry+https://github.com/rust-lang/crates.io-index" 1928 | checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" 1929 | dependencies = [ 1930 | "getrandom 0.2.16", 1931 | "libredox", 1932 | "thiserror 1.0.69", 1933 | ] 1934 | 1935 | [[package]] 1936 | name = "regex" 1937 | version = "1.11.2" 1938 | source = "registry+https://github.com/rust-lang/crates.io-index" 1939 | checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" 1940 | dependencies = [ 1941 | "aho-corasick 1.1.3", 1942 | "memchr", 1943 | "regex-automata", 1944 | "regex-syntax", 1945 | ] 1946 | 1947 | [[package]] 1948 | name = "regex-automata" 1949 | version = "0.4.10" 1950 | source = "registry+https://github.com/rust-lang/crates.io-index" 1951 | checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" 1952 | dependencies = [ 1953 | "aho-corasick 1.1.3", 1954 | "memchr", 1955 | "regex-syntax", 1956 | ] 1957 | 1958 | [[package]] 1959 | name = "regex-syntax" 1960 | version = "0.8.6" 1961 | source = "registry+https://github.com/rust-lang/crates.io-index" 1962 | checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" 1963 | 1964 | [[package]] 1965 | name = "ropey" 1966 | version = "1.6.1" 1967 | source = "registry+https://github.com/rust-lang/crates.io-index" 1968 | checksum = "93411e420bcd1a75ddd1dc3caf18c23155eda2c090631a85af21ba19e97093b5" 1969 | dependencies = [ 1970 | "smallvec", 1971 | "str_indices", 1972 | ] 1973 | 1974 | [[package]] 1975 | name = "rustc-demangle" 1976 | version = "0.1.26" 1977 | source = "registry+https://github.com/rust-lang/crates.io-index" 1978 | checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" 1979 | 1980 | [[package]] 1981 | name = "rustix" 1982 | version = "0.38.44" 1983 | source = "registry+https://github.com/rust-lang/crates.io-index" 1984 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 1985 | dependencies = [ 1986 | "bitflags 2.9.3", 1987 | "errno", 1988 | "libc", 1989 | "linux-raw-sys 0.4.15", 1990 | "windows-sys 0.59.0", 1991 | ] 1992 | 1993 | [[package]] 1994 | name = "rustix" 1995 | version = "1.0.8" 1996 | source = "registry+https://github.com/rust-lang/crates.io-index" 1997 | checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" 1998 | dependencies = [ 1999 | "bitflags 2.9.3", 2000 | "errno", 2001 | "libc", 2002 | "linux-raw-sys 0.9.4", 2003 | "windows-sys 0.60.2", 2004 | ] 2005 | 2006 | [[package]] 2007 | name = "rustversion" 2008 | version = "1.0.22" 2009 | source = "registry+https://github.com/rust-lang/crates.io-index" 2010 | checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" 2011 | 2012 | [[package]] 2013 | name = "ryu" 2014 | version = "1.0.20" 2015 | source = "registry+https://github.com/rust-lang/crates.io-index" 2016 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 2017 | 2018 | [[package]] 2019 | name = "same-file" 2020 | version = "1.0.6" 2021 | source = "registry+https://github.com/rust-lang/crates.io-index" 2022 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 2023 | dependencies = [ 2024 | "winapi-util", 2025 | ] 2026 | 2027 | [[package]] 2028 | name = "scopeguard" 2029 | version = "1.2.0" 2030 | source = "registry+https://github.com/rust-lang/crates.io-index" 2031 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 2032 | 2033 | [[package]] 2034 | name = "semver" 2035 | version = "1.0.26" 2036 | source = "registry+https://github.com/rust-lang/crates.io-index" 2037 | checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" 2038 | dependencies = [ 2039 | "serde", 2040 | ] 2041 | 2042 | [[package]] 2043 | name = "serde" 2044 | version = "1.0.219" 2045 | source = "registry+https://github.com/rust-lang/crates.io-index" 2046 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 2047 | dependencies = [ 2048 | "serde_derive", 2049 | ] 2050 | 2051 | [[package]] 2052 | name = "serde_derive" 2053 | version = "1.0.219" 2054 | source = "registry+https://github.com/rust-lang/crates.io-index" 2055 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 2056 | dependencies = [ 2057 | "proc-macro2", 2058 | "quote", 2059 | "syn 2.0.106", 2060 | ] 2061 | 2062 | [[package]] 2063 | name = "serde_json" 2064 | version = "1.0.143" 2065 | source = "registry+https://github.com/rust-lang/crates.io-index" 2066 | checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" 2067 | dependencies = [ 2068 | "itoa", 2069 | "memchr", 2070 | "ryu", 2071 | "serde", 2072 | ] 2073 | 2074 | [[package]] 2075 | name = "serde_repr" 2076 | version = "0.1.20" 2077 | source = "registry+https://github.com/rust-lang/crates.io-index" 2078 | checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" 2079 | dependencies = [ 2080 | "proc-macro2", 2081 | "quote", 2082 | "syn 2.0.106", 2083 | ] 2084 | 2085 | [[package]] 2086 | name = "sharded-slab" 2087 | version = "0.1.7" 2088 | source = "registry+https://github.com/rust-lang/crates.io-index" 2089 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 2090 | dependencies = [ 2091 | "lazy_static", 2092 | ] 2093 | 2094 | [[package]] 2095 | name = "shell-escape" 2096 | version = "0.1.5" 2097 | source = "registry+https://github.com/rust-lang/crates.io-index" 2098 | checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" 2099 | 2100 | [[package]] 2101 | name = "shlex" 2102 | version = "1.3.0" 2103 | source = "registry+https://github.com/rust-lang/crates.io-index" 2104 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 2105 | 2106 | [[package]] 2107 | name = "signal-hook" 2108 | version = "0.3.18" 2109 | source = "registry+https://github.com/rust-lang/crates.io-index" 2110 | checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" 2111 | dependencies = [ 2112 | "libc", 2113 | "signal-hook-registry", 2114 | ] 2115 | 2116 | [[package]] 2117 | name = "signal-hook-mio" 2118 | version = "0.2.4" 2119 | source = "registry+https://github.com/rust-lang/crates.io-index" 2120 | checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" 2121 | dependencies = [ 2122 | "libc", 2123 | "mio 1.0.4", 2124 | "signal-hook", 2125 | ] 2126 | 2127 | [[package]] 2128 | name = "signal-hook-registry" 2129 | version = "1.4.6" 2130 | source = "registry+https://github.com/rust-lang/crates.io-index" 2131 | checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" 2132 | dependencies = [ 2133 | "libc", 2134 | ] 2135 | 2136 | [[package]] 2137 | name = "siphasher" 2138 | version = "1.0.1" 2139 | source = "registry+https://github.com/rust-lang/crates.io-index" 2140 | checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" 2141 | 2142 | [[package]] 2143 | name = "slab" 2144 | version = "0.4.11" 2145 | source = "registry+https://github.com/rust-lang/crates.io-index" 2146 | checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" 2147 | 2148 | [[package]] 2149 | name = "smallvec" 2150 | version = "1.15.1" 2151 | source = "registry+https://github.com/rust-lang/crates.io-index" 2152 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 2153 | 2154 | [[package]] 2155 | name = "socket2" 2156 | version = "0.6.0" 2157 | source = "registry+https://github.com/rust-lang/crates.io-index" 2158 | checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" 2159 | dependencies = [ 2160 | "libc", 2161 | "windows-sys 0.59.0", 2162 | ] 2163 | 2164 | [[package]] 2165 | name = "static_assertions" 2166 | version = "1.1.0" 2167 | source = "registry+https://github.com/rust-lang/crates.io-index" 2168 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 2169 | 2170 | [[package]] 2171 | name = "stderrlog" 2172 | version = "0.6.0" 2173 | source = "registry+https://github.com/rust-lang/crates.io-index" 2174 | checksum = "61c910772f992ab17d32d6760e167d2353f4130ed50e796752689556af07dc6b" 2175 | dependencies = [ 2176 | "chrono", 2177 | "is-terminal", 2178 | "log", 2179 | "termcolor", 2180 | "thread_local", 2181 | ] 2182 | 2183 | [[package]] 2184 | name = "str_indices" 2185 | version = "0.4.4" 2186 | source = "registry+https://github.com/rust-lang/crates.io-index" 2187 | checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6" 2188 | 2189 | [[package]] 2190 | name = "strsim" 2191 | version = "0.8.0" 2192 | source = "registry+https://github.com/rust-lang/crates.io-index" 2193 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 2194 | 2195 | [[package]] 2196 | name = "strsim" 2197 | version = "0.10.0" 2198 | source = "registry+https://github.com/rust-lang/crates.io-index" 2199 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 2200 | 2201 | [[package]] 2202 | name = "strsim" 2203 | version = "0.11.1" 2204 | source = "registry+https://github.com/rust-lang/crates.io-index" 2205 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 2206 | 2207 | [[package]] 2208 | name = "strum" 2209 | version = "0.26.3" 2210 | source = "registry+https://github.com/rust-lang/crates.io-index" 2211 | checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" 2212 | dependencies = [ 2213 | "strum_macros", 2214 | ] 2215 | 2216 | [[package]] 2217 | name = "strum_macros" 2218 | version = "0.26.4" 2219 | source = "registry+https://github.com/rust-lang/crates.io-index" 2220 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 2221 | dependencies = [ 2222 | "heck", 2223 | "proc-macro2", 2224 | "quote", 2225 | "rustversion", 2226 | "syn 2.0.106", 2227 | ] 2228 | 2229 | [[package]] 2230 | name = "syn" 2231 | version = "1.0.109" 2232 | source = "registry+https://github.com/rust-lang/crates.io-index" 2233 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 2234 | dependencies = [ 2235 | "proc-macro2", 2236 | "quote", 2237 | "unicode-ident", 2238 | ] 2239 | 2240 | [[package]] 2241 | name = "syn" 2242 | version = "2.0.106" 2243 | source = "registry+https://github.com/rust-lang/crates.io-index" 2244 | checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" 2245 | dependencies = [ 2246 | "proc-macro2", 2247 | "quote", 2248 | "unicode-ident", 2249 | ] 2250 | 2251 | [[package]] 2252 | name = "tauri-winrt-notification" 2253 | version = "0.7.2" 2254 | source = "registry+https://github.com/rust-lang/crates.io-index" 2255 | checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9" 2256 | dependencies = [ 2257 | "quick-xml", 2258 | "thiserror 2.0.16", 2259 | "windows", 2260 | "windows-version", 2261 | ] 2262 | 2263 | [[package]] 2264 | name = "tempfile" 2265 | version = "3.21.0" 2266 | source = "registry+https://github.com/rust-lang/crates.io-index" 2267 | checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" 2268 | dependencies = [ 2269 | "fastrand", 2270 | "getrandom 0.3.3", 2271 | "once_cell", 2272 | "rustix 1.0.8", 2273 | "windows-sys 0.60.2", 2274 | ] 2275 | 2276 | [[package]] 2277 | name = "termcolor" 2278 | version = "1.1.3" 2279 | source = "registry+https://github.com/rust-lang/crates.io-index" 2280 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 2281 | dependencies = [ 2282 | "winapi-util", 2283 | ] 2284 | 2285 | [[package]] 2286 | name = "terminfo" 2287 | version = "0.7.5" 2288 | source = "registry+https://github.com/rust-lang/crates.io-index" 2289 | checksum = "da31aef70da0f6352dbcb462683eb4dd2bfad01cf3fc96cf204547b9a839a585" 2290 | dependencies = [ 2291 | "dirs", 2292 | "fnv", 2293 | "nom", 2294 | "phf", 2295 | "phf_codegen", 2296 | ] 2297 | 2298 | [[package]] 2299 | name = "textwrap" 2300 | version = "0.11.0" 2301 | source = "registry+https://github.com/rust-lang/crates.io-index" 2302 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 2303 | dependencies = [ 2304 | "unicode-width 0.1.14", 2305 | ] 2306 | 2307 | [[package]] 2308 | name = "thiserror" 2309 | version = "1.0.69" 2310 | source = "registry+https://github.com/rust-lang/crates.io-index" 2311 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 2312 | dependencies = [ 2313 | "thiserror-impl 1.0.69", 2314 | ] 2315 | 2316 | [[package]] 2317 | name = "thiserror" 2318 | version = "2.0.16" 2319 | source = "registry+https://github.com/rust-lang/crates.io-index" 2320 | checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" 2321 | dependencies = [ 2322 | "thiserror-impl 2.0.16", 2323 | ] 2324 | 2325 | [[package]] 2326 | name = "thiserror-impl" 2327 | version = "1.0.69" 2328 | source = "registry+https://github.com/rust-lang/crates.io-index" 2329 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 2330 | dependencies = [ 2331 | "proc-macro2", 2332 | "quote", 2333 | "syn 2.0.106", 2334 | ] 2335 | 2336 | [[package]] 2337 | name = "thiserror-impl" 2338 | version = "2.0.16" 2339 | source = "registry+https://github.com/rust-lang/crates.io-index" 2340 | checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" 2341 | dependencies = [ 2342 | "proc-macro2", 2343 | "quote", 2344 | "syn 2.0.106", 2345 | ] 2346 | 2347 | [[package]] 2348 | name = "thread_local" 2349 | version = "1.1.9" 2350 | source = "registry+https://github.com/rust-lang/crates.io-index" 2351 | checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" 2352 | dependencies = [ 2353 | "cfg-if 1.0.3", 2354 | ] 2355 | 2356 | [[package]] 2357 | name = "time" 2358 | version = "0.3.41" 2359 | source = "registry+https://github.com/rust-lang/crates.io-index" 2360 | checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" 2361 | dependencies = [ 2362 | "deranged", 2363 | "num-conv", 2364 | "powerfmt", 2365 | "serde", 2366 | "time-core", 2367 | ] 2368 | 2369 | [[package]] 2370 | name = "time-core" 2371 | version = "0.1.4" 2372 | source = "registry+https://github.com/rust-lang/crates.io-index" 2373 | checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" 2374 | 2375 | [[package]] 2376 | name = "tokio" 2377 | version = "1.47.1" 2378 | source = "registry+https://github.com/rust-lang/crates.io-index" 2379 | checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" 2380 | dependencies = [ 2381 | "backtrace", 2382 | "bytes", 2383 | "io-uring", 2384 | "libc", 2385 | "mio 1.0.4", 2386 | "parking_lot", 2387 | "pin-project-lite", 2388 | "signal-hook-registry", 2389 | "slab", 2390 | "socket2", 2391 | "tokio-macros", 2392 | "windows-sys 0.59.0", 2393 | ] 2394 | 2395 | [[package]] 2396 | name = "tokio-macros" 2397 | version = "2.5.0" 2398 | source = "registry+https://github.com/rust-lang/crates.io-index" 2399 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 2400 | dependencies = [ 2401 | "proc-macro2", 2402 | "quote", 2403 | "syn 2.0.106", 2404 | ] 2405 | 2406 | [[package]] 2407 | name = "toml_datetime" 2408 | version = "0.6.11" 2409 | source = "registry+https://github.com/rust-lang/crates.io-index" 2410 | checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" 2411 | 2412 | [[package]] 2413 | name = "toml_edit" 2414 | version = "0.22.27" 2415 | source = "registry+https://github.com/rust-lang/crates.io-index" 2416 | checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" 2417 | dependencies = [ 2418 | "indexmap", 2419 | "toml_datetime", 2420 | "winnow", 2421 | ] 2422 | 2423 | [[package]] 2424 | name = "tracing" 2425 | version = "0.1.41" 2426 | source = "registry+https://github.com/rust-lang/crates.io-index" 2427 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 2428 | dependencies = [ 2429 | "pin-project-lite", 2430 | "tracing-attributes", 2431 | "tracing-core", 2432 | ] 2433 | 2434 | [[package]] 2435 | name = "tracing-attributes" 2436 | version = "0.1.30" 2437 | source = "registry+https://github.com/rust-lang/crates.io-index" 2438 | checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" 2439 | dependencies = [ 2440 | "proc-macro2", 2441 | "quote", 2442 | "syn 2.0.106", 2443 | ] 2444 | 2445 | [[package]] 2446 | name = "tracing-core" 2447 | version = "0.1.34" 2448 | source = "registry+https://github.com/rust-lang/crates.io-index" 2449 | checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" 2450 | dependencies = [ 2451 | "once_cell", 2452 | "valuable", 2453 | ] 2454 | 2455 | [[package]] 2456 | name = "tracing-error" 2457 | version = "0.2.1" 2458 | source = "registry+https://github.com/rust-lang/crates.io-index" 2459 | checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" 2460 | dependencies = [ 2461 | "tracing", 2462 | "tracing-subscriber", 2463 | ] 2464 | 2465 | [[package]] 2466 | name = "tracing-log" 2467 | version = "0.2.0" 2468 | source = "registry+https://github.com/rust-lang/crates.io-index" 2469 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 2470 | dependencies = [ 2471 | "log", 2472 | "once_cell", 2473 | "tracing-core", 2474 | ] 2475 | 2476 | [[package]] 2477 | name = "tracing-subscriber" 2478 | version = "0.3.20" 2479 | source = "registry+https://github.com/rust-lang/crates.io-index" 2480 | checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" 2481 | dependencies = [ 2482 | "nu-ansi-term", 2483 | "sharded-slab", 2484 | "smallvec", 2485 | "thread_local", 2486 | "tracing-core", 2487 | "tracing-log", 2488 | ] 2489 | 2490 | [[package]] 2491 | name = "uds_windows" 2492 | version = "1.1.0" 2493 | source = "registry+https://github.com/rust-lang/crates.io-index" 2494 | checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" 2495 | dependencies = [ 2496 | "memoffset 0.9.1", 2497 | "tempfile", 2498 | "winapi 0.3.9", 2499 | ] 2500 | 2501 | [[package]] 2502 | name = "unicode-display-width" 2503 | version = "0.3.0" 2504 | source = "registry+https://github.com/rust-lang/crates.io-index" 2505 | checksum = "9a43273b656140aa2bb8e65351fe87c255f0eca706b2538a9bd4a590a3490bf3" 2506 | dependencies = [ 2507 | "unicode-segmentation", 2508 | ] 2509 | 2510 | [[package]] 2511 | name = "unicode-ident" 2512 | version = "1.0.18" 2513 | source = "registry+https://github.com/rust-lang/crates.io-index" 2514 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 2515 | 2516 | [[package]] 2517 | name = "unicode-segmentation" 2518 | version = "1.12.0" 2519 | source = "registry+https://github.com/rust-lang/crates.io-index" 2520 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 2521 | 2522 | [[package]] 2523 | name = "unicode-truncate" 2524 | version = "1.1.0" 2525 | source = "registry+https://github.com/rust-lang/crates.io-index" 2526 | checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" 2527 | dependencies = [ 2528 | "itertools", 2529 | "unicode-segmentation", 2530 | "unicode-width 0.1.14", 2531 | ] 2532 | 2533 | [[package]] 2534 | name = "unicode-width" 2535 | version = "0.1.14" 2536 | source = "registry+https://github.com/rust-lang/crates.io-index" 2537 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 2538 | 2539 | [[package]] 2540 | name = "unicode-width" 2541 | version = "0.2.0" 2542 | source = "registry+https://github.com/rust-lang/crates.io-index" 2543 | checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" 2544 | 2545 | [[package]] 2546 | name = "valuable" 2547 | version = "0.1.1" 2548 | source = "registry+https://github.com/rust-lang/crates.io-index" 2549 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 2550 | 2551 | [[package]] 2552 | name = "vec_map" 2553 | version = "0.8.2" 2554 | source = "registry+https://github.com/rust-lang/crates.io-index" 2555 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 2556 | 2557 | [[package]] 2558 | name = "version_check" 2559 | version = "0.9.5" 2560 | source = "registry+https://github.com/rust-lang/crates.io-index" 2561 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 2562 | 2563 | [[package]] 2564 | name = "walkdir" 2565 | version = "2.5.0" 2566 | source = "registry+https://github.com/rust-lang/crates.io-index" 2567 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 2568 | dependencies = [ 2569 | "same-file", 2570 | "winapi-util", 2571 | ] 2572 | 2573 | [[package]] 2574 | name = "wasi" 2575 | version = "0.11.1+wasi-snapshot-preview1" 2576 | source = "registry+https://github.com/rust-lang/crates.io-index" 2577 | checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 2578 | 2579 | [[package]] 2580 | name = "wasi" 2581 | version = "0.14.3+wasi-0.2.4" 2582 | source = "registry+https://github.com/rust-lang/crates.io-index" 2583 | checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" 2584 | dependencies = [ 2585 | "wit-bindgen", 2586 | ] 2587 | 2588 | [[package]] 2589 | name = "wasm-bindgen" 2590 | version = "0.2.100" 2591 | source = "registry+https://github.com/rust-lang/crates.io-index" 2592 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 2593 | dependencies = [ 2594 | "cfg-if 1.0.3", 2595 | "once_cell", 2596 | "rustversion", 2597 | "wasm-bindgen-macro", 2598 | ] 2599 | 2600 | [[package]] 2601 | name = "wasm-bindgen-backend" 2602 | version = "0.2.100" 2603 | source = "registry+https://github.com/rust-lang/crates.io-index" 2604 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 2605 | dependencies = [ 2606 | "bumpalo", 2607 | "log", 2608 | "proc-macro2", 2609 | "quote", 2610 | "syn 2.0.106", 2611 | "wasm-bindgen-shared", 2612 | ] 2613 | 2614 | [[package]] 2615 | name = "wasm-bindgen-macro" 2616 | version = "0.2.100" 2617 | source = "registry+https://github.com/rust-lang/crates.io-index" 2618 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 2619 | dependencies = [ 2620 | "quote", 2621 | "wasm-bindgen-macro-support", 2622 | ] 2623 | 2624 | [[package]] 2625 | name = "wasm-bindgen-macro-support" 2626 | version = "0.2.100" 2627 | source = "registry+https://github.com/rust-lang/crates.io-index" 2628 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 2629 | dependencies = [ 2630 | "proc-macro2", 2631 | "quote", 2632 | "syn 2.0.106", 2633 | "wasm-bindgen-backend", 2634 | "wasm-bindgen-shared", 2635 | ] 2636 | 2637 | [[package]] 2638 | name = "wasm-bindgen-shared" 2639 | version = "0.2.100" 2640 | source = "registry+https://github.com/rust-lang/crates.io-index" 2641 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 2642 | dependencies = [ 2643 | "unicode-ident", 2644 | ] 2645 | 2646 | [[package]] 2647 | name = "watchexec" 2648 | version = "1.17.2" 2649 | source = "registry+https://github.com/rust-lang/crates.io-index" 2650 | checksum = "38928d7ff5274e31594da2d46453a2c741fa340d1bf0ef6f2cb3e43537361265" 2651 | dependencies = [ 2652 | "clearscreen", 2653 | "command-group", 2654 | "derive_builder", 2655 | "glob", 2656 | "globset", 2657 | "lazy_static", 2658 | "log", 2659 | "nix 0.22.3", 2660 | "notify", 2661 | "walkdir", 2662 | "winapi 0.3.9", 2663 | ] 2664 | 2665 | [[package]] 2666 | name = "which" 2667 | version = "4.4.2" 2668 | source = "registry+https://github.com/rust-lang/crates.io-index" 2669 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 2670 | dependencies = [ 2671 | "either", 2672 | "home", 2673 | "once_cell", 2674 | "rustix 0.38.44", 2675 | ] 2676 | 2677 | [[package]] 2678 | name = "which" 2679 | version = "8.0.0" 2680 | source = "registry+https://github.com/rust-lang/crates.io-index" 2681 | checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d" 2682 | dependencies = [ 2683 | "env_home", 2684 | "rustix 1.0.8", 2685 | "winsafe", 2686 | ] 2687 | 2688 | [[package]] 2689 | name = "winapi" 2690 | version = "0.2.8" 2691 | source = "registry+https://github.com/rust-lang/crates.io-index" 2692 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 2693 | 2694 | [[package]] 2695 | name = "winapi" 2696 | version = "0.3.9" 2697 | source = "registry+https://github.com/rust-lang/crates.io-index" 2698 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2699 | dependencies = [ 2700 | "winapi-i686-pc-windows-gnu", 2701 | "winapi-x86_64-pc-windows-gnu", 2702 | ] 2703 | 2704 | [[package]] 2705 | name = "winapi-build" 2706 | version = "0.1.1" 2707 | source = "registry+https://github.com/rust-lang/crates.io-index" 2708 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 2709 | 2710 | [[package]] 2711 | name = "winapi-i686-pc-windows-gnu" 2712 | version = "0.4.0" 2713 | source = "registry+https://github.com/rust-lang/crates.io-index" 2714 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2715 | 2716 | [[package]] 2717 | name = "winapi-util" 2718 | version = "0.1.10" 2719 | source = "registry+https://github.com/rust-lang/crates.io-index" 2720 | checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" 2721 | dependencies = [ 2722 | "windows-sys 0.60.2", 2723 | ] 2724 | 2725 | [[package]] 2726 | name = "winapi-x86_64-pc-windows-gnu" 2727 | version = "0.4.0" 2728 | source = "registry+https://github.com/rust-lang/crates.io-index" 2729 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2730 | 2731 | [[package]] 2732 | name = "windows" 2733 | version = "0.61.3" 2734 | source = "registry+https://github.com/rust-lang/crates.io-index" 2735 | checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" 2736 | dependencies = [ 2737 | "windows-collections", 2738 | "windows-core", 2739 | "windows-future", 2740 | "windows-link", 2741 | "windows-numerics", 2742 | ] 2743 | 2744 | [[package]] 2745 | name = "windows-collections" 2746 | version = "0.2.0" 2747 | source = "registry+https://github.com/rust-lang/crates.io-index" 2748 | checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" 2749 | dependencies = [ 2750 | "windows-core", 2751 | ] 2752 | 2753 | [[package]] 2754 | name = "windows-core" 2755 | version = "0.61.2" 2756 | source = "registry+https://github.com/rust-lang/crates.io-index" 2757 | checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" 2758 | dependencies = [ 2759 | "windows-implement", 2760 | "windows-interface", 2761 | "windows-link", 2762 | "windows-result", 2763 | "windows-strings", 2764 | ] 2765 | 2766 | [[package]] 2767 | name = "windows-future" 2768 | version = "0.2.1" 2769 | source = "registry+https://github.com/rust-lang/crates.io-index" 2770 | checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" 2771 | dependencies = [ 2772 | "windows-core", 2773 | "windows-link", 2774 | "windows-threading", 2775 | ] 2776 | 2777 | [[package]] 2778 | name = "windows-implement" 2779 | version = "0.60.0" 2780 | source = "registry+https://github.com/rust-lang/crates.io-index" 2781 | checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" 2782 | dependencies = [ 2783 | "proc-macro2", 2784 | "quote", 2785 | "syn 2.0.106", 2786 | ] 2787 | 2788 | [[package]] 2789 | name = "windows-interface" 2790 | version = "0.59.1" 2791 | source = "registry+https://github.com/rust-lang/crates.io-index" 2792 | checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" 2793 | dependencies = [ 2794 | "proc-macro2", 2795 | "quote", 2796 | "syn 2.0.106", 2797 | ] 2798 | 2799 | [[package]] 2800 | name = "windows-link" 2801 | version = "0.1.3" 2802 | source = "registry+https://github.com/rust-lang/crates.io-index" 2803 | checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" 2804 | 2805 | [[package]] 2806 | name = "windows-numerics" 2807 | version = "0.2.0" 2808 | source = "registry+https://github.com/rust-lang/crates.io-index" 2809 | checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" 2810 | dependencies = [ 2811 | "windows-core", 2812 | "windows-link", 2813 | ] 2814 | 2815 | [[package]] 2816 | name = "windows-result" 2817 | version = "0.3.4" 2818 | source = "registry+https://github.com/rust-lang/crates.io-index" 2819 | checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" 2820 | dependencies = [ 2821 | "windows-link", 2822 | ] 2823 | 2824 | [[package]] 2825 | name = "windows-strings" 2826 | version = "0.4.2" 2827 | source = "registry+https://github.com/rust-lang/crates.io-index" 2828 | checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" 2829 | dependencies = [ 2830 | "windows-link", 2831 | ] 2832 | 2833 | [[package]] 2834 | name = "windows-sys" 2835 | version = "0.52.0" 2836 | source = "registry+https://github.com/rust-lang/crates.io-index" 2837 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2838 | dependencies = [ 2839 | "windows-targets 0.52.6", 2840 | ] 2841 | 2842 | [[package]] 2843 | name = "windows-sys" 2844 | version = "0.59.0" 2845 | source = "registry+https://github.com/rust-lang/crates.io-index" 2846 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 2847 | dependencies = [ 2848 | "windows-targets 0.52.6", 2849 | ] 2850 | 2851 | [[package]] 2852 | name = "windows-sys" 2853 | version = "0.60.2" 2854 | source = "registry+https://github.com/rust-lang/crates.io-index" 2855 | checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 2856 | dependencies = [ 2857 | "windows-targets 0.53.3", 2858 | ] 2859 | 2860 | [[package]] 2861 | name = "windows-targets" 2862 | version = "0.52.6" 2863 | source = "registry+https://github.com/rust-lang/crates.io-index" 2864 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2865 | dependencies = [ 2866 | "windows_aarch64_gnullvm 0.52.6", 2867 | "windows_aarch64_msvc 0.52.6", 2868 | "windows_i686_gnu 0.52.6", 2869 | "windows_i686_gnullvm 0.52.6", 2870 | "windows_i686_msvc 0.52.6", 2871 | "windows_x86_64_gnu 0.52.6", 2872 | "windows_x86_64_gnullvm 0.52.6", 2873 | "windows_x86_64_msvc 0.52.6", 2874 | ] 2875 | 2876 | [[package]] 2877 | name = "windows-targets" 2878 | version = "0.53.3" 2879 | source = "registry+https://github.com/rust-lang/crates.io-index" 2880 | checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" 2881 | dependencies = [ 2882 | "windows-link", 2883 | "windows_aarch64_gnullvm 0.53.0", 2884 | "windows_aarch64_msvc 0.53.0", 2885 | "windows_i686_gnu 0.53.0", 2886 | "windows_i686_gnullvm 0.53.0", 2887 | "windows_i686_msvc 0.53.0", 2888 | "windows_x86_64_gnu 0.53.0", 2889 | "windows_x86_64_gnullvm 0.53.0", 2890 | "windows_x86_64_msvc 0.53.0", 2891 | ] 2892 | 2893 | [[package]] 2894 | name = "windows-threading" 2895 | version = "0.1.0" 2896 | source = "registry+https://github.com/rust-lang/crates.io-index" 2897 | checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" 2898 | dependencies = [ 2899 | "windows-link", 2900 | ] 2901 | 2902 | [[package]] 2903 | name = "windows-version" 2904 | version = "0.1.4" 2905 | source = "registry+https://github.com/rust-lang/crates.io-index" 2906 | checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c" 2907 | dependencies = [ 2908 | "windows-link", 2909 | ] 2910 | 2911 | [[package]] 2912 | name = "windows_aarch64_gnullvm" 2913 | version = "0.52.6" 2914 | source = "registry+https://github.com/rust-lang/crates.io-index" 2915 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2916 | 2917 | [[package]] 2918 | name = "windows_aarch64_gnullvm" 2919 | version = "0.53.0" 2920 | source = "registry+https://github.com/rust-lang/crates.io-index" 2921 | checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 2922 | 2923 | [[package]] 2924 | name = "windows_aarch64_msvc" 2925 | version = "0.52.6" 2926 | source = "registry+https://github.com/rust-lang/crates.io-index" 2927 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2928 | 2929 | [[package]] 2930 | name = "windows_aarch64_msvc" 2931 | version = "0.53.0" 2932 | source = "registry+https://github.com/rust-lang/crates.io-index" 2933 | checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 2934 | 2935 | [[package]] 2936 | name = "windows_i686_gnu" 2937 | version = "0.52.6" 2938 | source = "registry+https://github.com/rust-lang/crates.io-index" 2939 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2940 | 2941 | [[package]] 2942 | name = "windows_i686_gnu" 2943 | version = "0.53.0" 2944 | source = "registry+https://github.com/rust-lang/crates.io-index" 2945 | checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 2946 | 2947 | [[package]] 2948 | name = "windows_i686_gnullvm" 2949 | version = "0.52.6" 2950 | source = "registry+https://github.com/rust-lang/crates.io-index" 2951 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2952 | 2953 | [[package]] 2954 | name = "windows_i686_gnullvm" 2955 | version = "0.53.0" 2956 | source = "registry+https://github.com/rust-lang/crates.io-index" 2957 | checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 2958 | 2959 | [[package]] 2960 | name = "windows_i686_msvc" 2961 | version = "0.52.6" 2962 | source = "registry+https://github.com/rust-lang/crates.io-index" 2963 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2964 | 2965 | [[package]] 2966 | name = "windows_i686_msvc" 2967 | version = "0.53.0" 2968 | source = "registry+https://github.com/rust-lang/crates.io-index" 2969 | checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 2970 | 2971 | [[package]] 2972 | name = "windows_x86_64_gnu" 2973 | version = "0.52.6" 2974 | source = "registry+https://github.com/rust-lang/crates.io-index" 2975 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2976 | 2977 | [[package]] 2978 | name = "windows_x86_64_gnu" 2979 | version = "0.53.0" 2980 | source = "registry+https://github.com/rust-lang/crates.io-index" 2981 | checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 2982 | 2983 | [[package]] 2984 | name = "windows_x86_64_gnullvm" 2985 | version = "0.52.6" 2986 | source = "registry+https://github.com/rust-lang/crates.io-index" 2987 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2988 | 2989 | [[package]] 2990 | name = "windows_x86_64_gnullvm" 2991 | version = "0.53.0" 2992 | source = "registry+https://github.com/rust-lang/crates.io-index" 2993 | checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 2994 | 2995 | [[package]] 2996 | name = "windows_x86_64_msvc" 2997 | version = "0.52.6" 2998 | source = "registry+https://github.com/rust-lang/crates.io-index" 2999 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 3000 | 3001 | [[package]] 3002 | name = "windows_x86_64_msvc" 3003 | version = "0.53.0" 3004 | source = "registry+https://github.com/rust-lang/crates.io-index" 3005 | checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 3006 | 3007 | [[package]] 3008 | name = "winnow" 3009 | version = "0.7.13" 3010 | source = "registry+https://github.com/rust-lang/crates.io-index" 3011 | checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" 3012 | dependencies = [ 3013 | "memchr", 3014 | ] 3015 | 3016 | [[package]] 3017 | name = "winsafe" 3018 | version = "0.0.19" 3019 | source = "registry+https://github.com/rust-lang/crates.io-index" 3020 | checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" 3021 | 3022 | [[package]] 3023 | name = "wit-bindgen" 3024 | version = "0.45.0" 3025 | source = "registry+https://github.com/rust-lang/crates.io-index" 3026 | checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" 3027 | 3028 | [[package]] 3029 | name = "ws2_32-sys" 3030 | version = "0.2.1" 3031 | source = "registry+https://github.com/rust-lang/crates.io-index" 3032 | checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 3033 | dependencies = [ 3034 | "winapi 0.2.8", 3035 | "winapi-build", 3036 | ] 3037 | 3038 | [[package]] 3039 | name = "zbus" 3040 | version = "5.10.0" 3041 | source = "registry+https://github.com/rust-lang/crates.io-index" 3042 | checksum = "67a073be99ace1adc48af593701c8015cd9817df372e14a1a6b0ee8f8bf043be" 3043 | dependencies = [ 3044 | "async-broadcast", 3045 | "async-executor", 3046 | "async-io", 3047 | "async-lock", 3048 | "async-process", 3049 | "async-recursion", 3050 | "async-task", 3051 | "async-trait", 3052 | "blocking", 3053 | "enumflags2", 3054 | "event-listener", 3055 | "futures-core", 3056 | "futures-lite", 3057 | "hex", 3058 | "nix 0.30.1", 3059 | "ordered-stream", 3060 | "serde", 3061 | "serde_repr", 3062 | "tracing", 3063 | "uds_windows", 3064 | "windows-sys 0.60.2", 3065 | "winnow", 3066 | "zbus_macros", 3067 | "zbus_names", 3068 | "zvariant", 3069 | ] 3070 | 3071 | [[package]] 3072 | name = "zbus_macros" 3073 | version = "5.10.0" 3074 | source = "registry+https://github.com/rust-lang/crates.io-index" 3075 | checksum = "0e80cd713a45a49859dcb648053f63265f4f2851b6420d47a958e5697c68b131" 3076 | dependencies = [ 3077 | "proc-macro-crate", 3078 | "proc-macro2", 3079 | "quote", 3080 | "syn 2.0.106", 3081 | "zbus_names", 3082 | "zvariant", 3083 | "zvariant_utils", 3084 | ] 3085 | 3086 | [[package]] 3087 | name = "zbus_names" 3088 | version = "4.2.0" 3089 | source = "registry+https://github.com/rust-lang/crates.io-index" 3090 | checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" 3091 | dependencies = [ 3092 | "serde", 3093 | "static_assertions", 3094 | "winnow", 3095 | "zvariant", 3096 | ] 3097 | 3098 | [[package]] 3099 | name = "zvariant" 3100 | version = "5.7.0" 3101 | source = "registry+https://github.com/rust-lang/crates.io-index" 3102 | checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" 3103 | dependencies = [ 3104 | "endi", 3105 | "enumflags2", 3106 | "serde", 3107 | "winnow", 3108 | "zvariant_derive", 3109 | "zvariant_utils", 3110 | ] 3111 | 3112 | [[package]] 3113 | name = "zvariant_derive" 3114 | version = "5.7.0" 3115 | source = "registry+https://github.com/rust-lang/crates.io-index" 3116 | checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" 3117 | dependencies = [ 3118 | "proc-macro-crate", 3119 | "proc-macro2", 3120 | "quote", 3121 | "syn 2.0.106", 3122 | "zvariant_utils", 3123 | ] 3124 | 3125 | [[package]] 3126 | name = "zvariant_utils" 3127 | version = "3.2.1" 3128 | source = "registry+https://github.com/rust-lang/crates.io-index" 3129 | checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" 3130 | dependencies = [ 3131 | "proc-macro2", 3132 | "quote", 3133 | "serde", 3134 | "syn 2.0.106", 3135 | "winnow", 3136 | ] 3137 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dj-cli" 3 | version = "0.1.0" 4 | description = "A CLI tool for DJs to download MP3s from YouTube" 5 | authors = ["Henryoman "] 6 | license = "MIT" 7 | edition = "2024" 8 | readme = "README.md" 9 | repository = "https://github.com/henryoman/dj-cli" 10 | 11 | [dependencies] 12 | crossterm = { version = "0.29.0", features = ["event-stream"] } 13 | futures = "0.3.31" 14 | ratatui = "0.29.0" 15 | tokio = { version = "1.47.1", features = ["full"] } 16 | color-eyre = "0.6.5" 17 | tracing = "0.1.41" 18 | tracing-subscriber = "0.3.20" 19 | 20 | regex = "1.11.2" 21 | 22 | [dev-dependencies] 23 | cargo-watch = "8.5.3" 24 | rat-text = "1.0.5" 25 | which = "8.0.0" 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Henry Oman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | dj-cli logo 3 |

4 | 5 |

DJ-CLI

6 |

Professional Terminal Interface for YouTube MP3 Downloads

7 | 8 |

9 | 10 | Crates.io version 11 | 12 | 13 | docs.rs status 14 | 15 | 16 | Build Status 17 | 18 | 19 | GitHub stars 20 | 21 | 22 | License: MIT 23 | 24 |

25 | 26 | --- 27 | 28 | ## Interface Preview 29 | 30 |

31 | DJ-CLI terminal interface 32 |

33 | 34 | Example of the terminal interface displaying status information and keyboard controls. 35 | 36 | --- 37 | 38 | ## Features 39 | 40 | ### Core Functionality 41 | - **Efficient downloads** using the [`yt-dlp`](https://github.com/yt-dlp/yt-dlp) backend 42 | - **High-quality audio extraction** supporting 128kbps and 256kbps MP3 output 43 | - **URL extraction** from clipboard text 44 | - **Asynchronous operations** with real-time progress updates 45 | 46 | ### Terminal User Interface 47 | - **Terminal interface** powered by [`ratatui`](https://ratatui.rs) 48 | - **Responsive layout** that adapts to terminal size 49 | - **Real-time status updates** with download progress and error handling 50 | - **Keyboard navigation** with intuitive controls 51 | - **Focus management** for consistent user experience 52 | 53 | ### Reliability & Performance 54 | - **Robust error handling** - graceful failures that don't crash the interface 55 | - **Input sanitization** - automatically cleans and validates pasted content 56 | - **Memory-safe operations** with input length limits and cleanup 57 | - **Cross-platform support**: macOS, Linux, Windows (via WSL) 58 | - **Zero external dependencies** beyond yt-dlp and ffmpeg 59 | 60 | ### File Management 61 | - **Automatic organization** - downloads save directly to your Downloads folder 62 | - **Metadata embedding** - includes thumbnails and track information 63 | - **Filename sanitization** - handles special characters and long titles 64 | - **Duplicate detection** - smart handling of existing files 65 | 66 | --- 67 | 68 | ## Quick Start 69 | 70 | ### Installation Options 71 | 72 | #### Option 1: Install from Crates.io (Recommended) 73 | ```bash 74 | cargo install dj-cli 75 | ``` 76 | 77 | #### Option 2: Build from Source 78 | ```bash 79 | git clone https://github.com/henryoman/dj-cli.git 80 | cd dj-cli 81 | cargo build --release 82 | cargo install --path . 83 | ``` 84 | 85 | #### Option 3: Run Directly 86 | ```bash 87 | git clone https://github.com/henryoman/dj-cli.git 88 | cd dj-cli 89 | cargo run --release 90 | ``` 91 | 92 | ### First Run 93 | ```bash 94 | # Launch the interactive TUI 95 | dj-cli 96 | 97 | # Or download directly (non-interactive) 98 | dj-cli "https://www.youtube.com/watch?v=dQw4w9WgXcQ" 99 | ``` 100 | 101 | --- 102 | 103 | ## Prerequisites & Dependencies 104 | 105 | ### Required Software 106 | 107 | #### 1. Rust Toolchain 108 | DJ-CLI requires **Rust 1.78 or later**. Install via [`rustup`](https://www.rust-lang.org/tools/install): 109 | 110 | ```bash 111 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 112 | source ~/.cargo/env 113 | ``` 114 | 115 | #### 2. yt-dlp (Core Download Engine) 116 | Install the latest version of yt-dlp: 117 | 118 | ```bash 119 | # macOS (Homebrew) 120 | brew install yt-dlp 121 | 122 | # Ubuntu/Debian 123 | sudo apt update && sudo apt install yt-dlp 124 | 125 | # Arch Linux 126 | sudo pacman -S yt-dlp 127 | 128 | # Or via pip (universal) 129 | pip install yt-dlp 130 | ``` 131 | 132 | #### 3. FFmpeg (Audio Processing) 133 | Required for audio extraction and format conversion: 134 | 135 | ```bash 136 | # macOS (Homebrew) 137 | brew install ffmpeg 138 | 139 | # Ubuntu/Debian 140 | sudo apt update && sudo apt install ffmpeg 141 | 142 | # Arch Linux 143 | sudo pacman -S ffmpeg 144 | 145 | # Windows (Chocolatey) 146 | choco install ffmpeg 147 | ``` 148 | 149 | ### Verification 150 | Test your setup: 151 | ```bash 152 | yt-dlp --version 153 | ffmpeg -version 154 | cargo --version 155 | ``` 156 | 157 | --- 158 | 159 | ## Comprehensive Usage Guide 160 | 161 | ### Single Download Mode 162 | 163 | 1. **Launch DJ-CLI** 164 | ```bash 165 | dj-cli 166 | ``` 167 | 168 | 2. **Paste YouTube URL** 169 | - Simply paste any YouTube URL into the input field 170 | - DJ-CLI automatically extracts and cleans the URL from messy clipboard content 171 | 172 | 3. **Choose Quality & Download** 173 | - **Enter** for default 128kbps download 174 | - **Ctrl+1** for quick 128kbps download 175 | - **Ctrl+2** for quick 256kbps download 176 | 177 | ### Advanced Features 178 | 179 | #### Smart Input Handling 180 | - **Paste any text** containing YouTube URLs - DJ-CLI extracts them automatically 181 | - **F5** to clean and extract URLs from current input 182 | - **Input validation** prevents invalid URLs from processing 183 | - **Length limits** protect against memory issues (500 chars max) 184 | 185 | #### Keyboard Shortcuts 186 | | Shortcut | Function | 187 | |----------|----------| 188 | | **Ctrl+C** | Quit application | 189 | | **Esc** | Exit application | 190 | | **Enter** | Download | 191 | | **Ctrl+1** | Quick 128kbps download | 192 | | **Ctrl+2** | Quick 256kbps download | 193 | | **F5** | Clean and extract URL from input | 194 | | **Delete** | Clear input field | 195 | | **Backspace** | Remove last character | 196 | 197 | --- 198 | 199 | ## Configuration & Customization 200 | 201 | ### Output Directory 202 | Files are automatically saved to your system's Downloads folder: 203 | - **macOS**: `~/Downloads/` 204 | - **Linux**: `~/Downloads/` 205 | - **Windows**: `%USERPROFILE%\Downloads\` 206 | 207 | ### Audio Quality Options 208 | 209 | | Quality | Bitrate | Use Case | 210 | |---------|---------|----------| 211 | | **128kbps** | Standard quality | General listening, smaller files | 212 | | **256kbps** | High quality | Audiophile listening, DJ sets | 213 | 214 | ### File Naming 215 | Downloaded files use the format: `[Video Title].mp3` 216 | - Special characters are automatically sanitized 217 | - Long titles are handled gracefully 218 | - Metadata and thumbnails are embedded automatically 219 | 220 | --- 221 | 222 | ## Architecture & Technical Details 223 | 224 | ### Built With Modern Rust 225 | - **[Tokio](https://tokio.rs)** - Async runtime for non-blocking operations 226 | - **[Ratatui](https://ratatui.rs)** - Terminal UI framework with rich widgets 227 | - **[Crossterm](https://github.com/crossterm-rs/crossterm)** - Cross-platform terminal manipulation 228 | - **[Color-eyre](https://github.com/yaahc/color-eyre)** - Enhanced error reporting 229 | - **[Tracing](https://github.com/tokio-rs/tracing)** - Structured logging 230 | - **[Regex](https://github.com/rust-lang/regex)** - URL pattern matching 231 | 232 | ### Performance Characteristics 233 | - **Memory-efficient**: Smart input limiting and cleanup 234 | - **CPU-light**: Async operations prevent blocking 235 | - **Storage-aware**: Downloads to standard user directories 236 | - **Network-optimized**: Leverages yt-dlp's efficient downloading 237 | 238 | ### Code Quality 239 | - **Memory safety** through Rust's ownership system 240 | - **Error handling** with graceful degradation 241 | - **Input validation** and sanitization throughout 242 | - **Modular architecture** for maintainability 243 | 244 | --- 245 | 246 | ## Troubleshooting 247 | 248 | ### Common Issues 249 | 250 | #### "yt-dlp not found" 251 | ```bash 252 | # Ensure yt-dlp is installed and in PATH 253 | which yt-dlp 254 | # If not found, install via your package manager 255 | brew install yt-dlp # macOS 256 | ``` 257 | 258 | #### "Download failed" 259 | ```bash 260 | # Check if URL is accessible 261 | yt-dlp --list-formats [YOUR_URL] 262 | # Update yt-dlp to latest version 263 | pip install -U yt-dlp 264 | ``` 265 | 266 | #### "Permission denied" in Downloads folder 267 | ```bash 268 | # Check Downloads folder permissions 269 | ls -la ~/Downloads/ 270 | # Create if missing 271 | mkdir -p ~/Downloads/ 272 | ``` 273 | 274 | #### Audio conversion fails 275 | ```bash 276 | # Verify ffmpeg installation 277 | ffmpeg -version 278 | # Reinstall if needed 279 | brew reinstall ffmpeg # macOS 280 | ``` 281 | 282 | ### Debug Mode 283 | For detailed error information: 284 | ```bash 285 | # Enable verbose logging (modify source) 286 | RUST_LOG=debug cargo run 287 | ``` 288 | 289 | --- 290 | 291 | ## Updates & Maintenance 292 | 293 | ### Staying Current 294 | ```bash 295 | # Update DJ-CLI 296 | cargo install dj-cli --force 297 | 298 | # Update yt-dlp (important for YouTube compatibility) 299 | pip install -U yt-dlp 300 | 301 | # Update dependencies when building from source 302 | cd dj-cli 303 | cargo update 304 | ``` 305 | 306 | ### Version Compatibility 307 | - **Minimum Rust version**: 1.78.0 308 | - **Tested yt-dlp versions**: 2023.12.30+ 309 | - **Supported platforms**: macOS 10.15+, Ubuntu 20.04+, Windows 10+ (WSL) 310 | 311 | --- 312 | 313 | ## Contributing 314 | 315 | Contributions are welcome. To get started: 316 | 317 | ### Development Setup 318 | ```bash 319 | # Clone and setup development environment 320 | git clone https://github.com/henryoman/dj-cli.git 321 | cd dj-cli 322 | cargo build 323 | cargo test 324 | 325 | # Install development tools 326 | cargo install cargo-watch 327 | ``` 328 | 329 | ### Code Standards 330 | ```bash 331 | # Format code 332 | cargo fmt 333 | 334 | # Lint with Clippy 335 | cargo clippy --all-targets --all-features -- -D warnings 336 | 337 | # Run tests 338 | cargo test 339 | ``` 340 | 341 | ### Contribution Workflow 342 | 1. **Fork** the repository 343 | 2. **Create** a feature branch: `git checkout -b feature/amazing-feature` 344 | 3. **Make** your changes with tests 345 | 4. **Ensure** all checks pass: `cargo fmt && cargo clippy && cargo test` 346 | 5. **Commit** with clear messages: `git commit -m 'Add amazing feature'` 347 | 6. **Push** to your fork: `git push origin feature/amazing-feature` 348 | 7. **Open** a Pull Request with detailed description 349 | 350 | ### Areas for Contribution 351 | - UI/UX improvements 352 | - Performance optimizations 353 | - Additional audio formats (FLAC, AAC) 354 | - Configuration file support 355 | - Internationalization 356 | - Documentation improvements 357 | 358 | --- 359 | 360 | ## License 361 | 362 | This project is licensed under the **MIT License** - see the [LICENSE](./LICENSE) file for complete details. 363 | 364 | ``` 365 | MIT License 366 | 367 | Copyright (c) 2024 Henryoman 368 | 369 | Permission is hereby granted, free of charge, to any person obtaining a copy 370 | of this software and associated documentation files... 371 | ``` 372 | 373 | --- 374 | 375 | ## Acknowledgments 376 | 377 | - **[yt-dlp team](https://github.com/yt-dlp/yt-dlp)** - Powerful YouTube download engine 378 | - **[Ratatui community](https://ratatui.rs)** - Excellent terminal UI framework 379 | - **[Orhun Parmaksız](https://github.com/orhun)** - Maintainer of Ratatui and open source champion from Ankara, Turkey 380 | - **[Rust community](https://www.rust-lang.org)** - Amazing language and ecosystem 381 | 382 | --- 383 | 384 | ## Project Stats 385 | 386 | - **Language**: Rust 387 | - **Lines of Code**: ~850+ 388 | - **Dependencies**: 16 (carefully chosen) 389 | - **Binary Size**: ~2MB (optimized) 390 | - **Performance**: Downloads limited only by network speed 391 | 392 | --- 393 | 394 |

395 | Built with Rust
396 | Terminal-based YouTube audio downloads 397 |

398 | -------------------------------------------------------------------------------- /interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henryoman/dj-cli/5e86fa3a38eb6acd9590b177c4ef2e545703410d/interface.png -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/henryoman/dj-cli/5e86fa3a38eb6acd9590b177c4ef2e545703410d/logo.png -------------------------------------------------------------------------------- /src/app.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::Result; 2 | use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers}; 3 | use ratatui::{DefaultTerminal, Frame}; 4 | // Removed ratatui_input for simplicity 5 | use regex::Regex; 6 | use std::path::PathBuf; 7 | use std::time::{Duration, UNIX_EPOCH}; 8 | use std::{fs, process::Stdio}; 9 | use tracing::{error, info, warn}; 10 | 11 | // Maximum input length to prevent memory issues and UI corruption 12 | const MAX_INPUT_LENGTH: usize = 500; 13 | const MAX_PASTE_LENGTH: usize = 10000; 14 | 15 | /// Application state 16 | #[derive(Debug)] 17 | pub struct App { 18 | /// Should the application exit? 19 | pub running: bool, 20 | /// YouTube URL input 21 | pub input: String, 22 | /// Current status message 23 | pub status_message: String, 24 | /// Download status 25 | pub download_status: DownloadStatus, 26 | /// Focus state (Input or Convert button) 27 | pub focus: Focus, 28 | /// Download history for display 29 | pub download_history: Vec, 30 | } 31 | 32 | #[derive(Debug, Clone)] 33 | pub enum DownloadStatus { 34 | Idle, 35 | Downloading, 36 | Success(String), 37 | Error(String), 38 | } 39 | 40 | #[derive(Debug, Clone, PartialEq)] 41 | pub enum Focus { 42 | Input, 43 | } 44 | 45 | impl Default for App { 46 | fn default() -> Self { 47 | Self::new() 48 | } 49 | } 50 | 51 | impl App { 52 | pub fn new() -> Self { 53 | Self { 54 | running: true, 55 | input: String::new(), 56 | status_message: "Paste a YouTube URL and press Enter to download MP3".to_string(), 57 | download_status: DownloadStatus::Idle, 58 | focus: Focus::Input, 59 | download_history: Vec::new(), 60 | } 61 | } 62 | 63 | /// Main application loop 64 | pub async fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> { 65 | info!("Starting main app loop"); 66 | 67 | while self.running { 68 | // Draw UI 69 | terminal.draw(|frame| self.draw(frame))?; 70 | // Handle events 71 | if event::poll(Duration::from_millis(100))? { 72 | if let Event::Key(key) = event::read()? { 73 | if key.kind == KeyEventKind::Press { 74 | self.handle_key_event(key).await?; 75 | } 76 | } 77 | } 78 | } 79 | 80 | info!("App loop finished"); 81 | Ok(()) 82 | } 83 | 84 | /// Draw the application UI 85 | fn draw(&mut self, frame: &mut Frame) { 86 | crate::ui::render(frame, self); 87 | } 88 | 89 | /// Sanitize and validate input text 90 | fn sanitize_input(&mut self, input: &str) -> String { 91 | // First, truncate if too long 92 | let truncated = if input.len() > MAX_PASTE_LENGTH { 93 | warn!( 94 | "Input truncated from {} to {} characters", 95 | input.len(), 96 | MAX_PASTE_LENGTH 97 | ); 98 | &input[..MAX_PASTE_LENGTH] 99 | } else { 100 | input 101 | }; 102 | 103 | // Try to extract YouTube URL from the text 104 | if let Some(url) = self.extract_youtube_url(truncated) { 105 | info!("Extracted YouTube URL: {}", url); 106 | return url; 107 | } 108 | 109 | // If no URL found, clean the text and apply length limit 110 | let cleaned = self.clean_text(truncated); 111 | if cleaned.len() > MAX_INPUT_LENGTH { 112 | warn!( 113 | "Cleaned input truncated from {} to {} characters", 114 | cleaned.len(), 115 | MAX_INPUT_LENGTH 116 | ); 117 | cleaned[..MAX_INPUT_LENGTH].to_string() 118 | } else { 119 | cleaned 120 | } 121 | } 122 | 123 | /// Extract YouTube URL from messy text 124 | fn extract_youtube_url(&self, text: &str) -> Option { 125 | // YouTube URL patterns (in order of preference) 126 | let patterns = [ 127 | // Full URLs with https 128 | r"https://(?:www\.)?youtube\.com/watch\?v=([a-zA-Z0-9_-]+)(?:[&\w=]*)?", 129 | r"https://youtu\.be/([a-zA-Z0-9_-]+)(?:\?[&\w=]*)?", 130 | // URLs without https 131 | r"(?:www\.)?youtube\.com/watch\?v=([a-zA-Z0-9_-]+)(?:[&\w=]*)?", 132 | r"youtu\.be/([a-zA-Z0-9_-]+)(?:\?[&\w=]*)?", 133 | // Just the watch part 134 | r"watch\?v=([a-zA-Z0-9_-]+)(?:[&\w=]*)?", 135 | ]; 136 | 137 | for pattern in &patterns { 138 | if let Ok(regex) = Regex::new(pattern) { 139 | if let Some(captures) = regex.captures(text) { 140 | if let Some(video_id) = captures.get(1) { 141 | let url = format!("https://www.youtube.com/watch?v={}", video_id.as_str()); 142 | info!("Extracted YouTube URL from pattern '{}': {}", pattern, url); 143 | return Some(url); 144 | } 145 | } 146 | } 147 | } 148 | 149 | None 150 | } 151 | 152 | /// Clean text by removing control characters and normalizing whitespace 153 | fn clean_text(&self, text: &str) -> String { 154 | text.chars() 155 | .filter(|c| { 156 | // Keep printable ASCII, basic Unicode, and essential whitespace 157 | c.is_ascii_graphic() || c.is_ascii_whitespace() || (*c as u32) > 127 158 | }) 159 | .collect::() 160 | .split_whitespace() // Normalize whitespace 161 | .collect::>() 162 | .join(" ") 163 | } 164 | 165 | /// Handle character input with proper sanitization 166 | fn handle_char_input(&mut self, c: char) { 167 | // Check if adding this character would exceed the limit 168 | if self.input.len() >= MAX_INPUT_LENGTH { 169 | warn!( 170 | "Input at maximum length ({}), ignoring character", 171 | MAX_INPUT_LENGTH 172 | ); 173 | self.status_message = format!("Input limit reached ({MAX_INPUT_LENGTH} characters)"); 174 | return; 175 | } 176 | 177 | // Filter out problematic characters 178 | if c.is_control() && c != '\t' { 179 | warn!("Ignoring control character: {:?}", c); 180 | return; 181 | } 182 | 183 | self.input.push(c); 184 | 185 | // Clear any previous status messages when user types normally 186 | if self.status_message.starts_with("Input limit reached") 187 | || self.status_message.starts_with("Large input sanitized") 188 | { 189 | self.status_message.clear(); 190 | } 191 | } 192 | 193 | /// Handle paste operation with sanitization 194 | fn handle_paste(&mut self, pasted_text: &str) { 195 | let original_len = pasted_text.len(); 196 | let sanitized = self.sanitize_input(pasted_text); 197 | 198 | if sanitized != pasted_text { 199 | if original_len > MAX_PASTE_LENGTH { 200 | self.status_message = format!( 201 | "Large input sanitized: {} → {} chars (extracted URL or cleaned text)", 202 | original_len, 203 | sanitized.len() 204 | ); 205 | } else { 206 | self.status_message = "Input cleaned and URL extracted".to_string(); 207 | } 208 | info!( 209 | "Input sanitized: original {} chars → {} chars", 210 | original_len, 211 | sanitized.len() 212 | ); 213 | } 214 | 215 | // Replace the current input with sanitized content 216 | self.input = sanitized; 217 | } 218 | 219 | /// Handle keyboard events with improved error handling and input sanitization 220 | async fn handle_key_event(&mut self, key: KeyEvent) -> Result<()> { 221 | // Global quit command 222 | if key.modifiers.contains(KeyModifiers::CONTROL) && key.code == KeyCode::Char('c') { 223 | info!("User quit with Ctrl+C"); 224 | self.running = false; 225 | return Ok(()); 226 | } 227 | 228 | // Use a separate method for handling that can't crash the UI 229 | if let Err(e) = self.handle_key_event_safe(key).await { 230 | error!("Error handling key event: {}", e); 231 | self.status_message = format!("Error: {e}"); 232 | // Don't crash the UI - just show the error message 233 | } 234 | 235 | Ok(()) 236 | } 237 | 238 | /// Safe key event handling that catches errors 239 | async fn handle_key_event_safe(&mut self, key: KeyEvent) -> Result<()> { 240 | match key.code { 241 | KeyCode::Esc => { 242 | self.running = false; 243 | } 244 | KeyCode::Enter => { 245 | if !self.input.trim().is_empty() { 246 | self.start_download(128).await?; 247 | } 248 | } 249 | KeyCode::Backspace => { 250 | self.input.pop(); 251 | } 252 | KeyCode::Delete => { 253 | self.input.clear(); 254 | } 255 | KeyCode::Tab => { 256 | // Tab does nothing now since we only have input focus 257 | // Keeping this for compatibility but it doesn't change focus 258 | } 259 | KeyCode::F(5) => { 260 | // F5 to clear input and extract URL from current content 261 | if !self.input.is_empty() { 262 | let original = self.input.clone(); 263 | self.handle_paste(&original); 264 | } 265 | } 266 | KeyCode::Char('1') if key.modifiers.contains(KeyModifiers::CONTROL) => { 267 | if !self.input.trim().is_empty() { 268 | self.start_download(128).await?; 269 | } 270 | } 271 | KeyCode::Char('2') if key.modifiers.contains(KeyModifiers::CONTROL) => { 272 | if !self.input.trim().is_empty() { 273 | self.start_download(256).await?; 274 | } 275 | } 276 | KeyCode::Char('v') if key.modifiers.contains(KeyModifiers::CONTROL) => { 277 | // Handle Ctrl+V paste - for now just inform user about F5 278 | self.status_message = 279 | "💡 Paste detected! Press F5 to clean and extract URL from pasted content" 280 | .to_string(); 281 | info!("Ctrl+V detected - user should use F5 for URL extraction"); 282 | } 283 | KeyCode::Char('a') if key.modifiers.contains(KeyModifiers::CONTROL) => { 284 | // Handle Ctrl+A - select all (just clear input for simplicity) 285 | info!("Ctrl+A detected - clearing input"); 286 | } 287 | KeyCode::Char(c) => { 288 | if key.modifiers.contains(KeyModifiers::CONTROL) { 289 | // Ignore other Ctrl+char combinations 290 | } else { 291 | // Handle regular character input 292 | self.handle_char_input(c); 293 | } 294 | } 295 | _ => {} 296 | } 297 | 298 | Ok(()) 299 | } 300 | 301 | /// Start downloading the YouTube video as MP3 with robust error handling 302 | async fn start_download(&mut self, bitrate: u32) -> Result<()> { 303 | let url = self.input.trim(); 304 | 305 | if url.is_empty() { 306 | self.status_message = "Please enter a YouTube URL".to_string(); 307 | warn!("Empty URL provided"); 308 | return Ok(()); 309 | } 310 | 311 | if !url.contains("youtube.com") && !url.contains("youtu.be") { 312 | self.status_message = "Please enter a valid YouTube URL".to_string(); 313 | warn!("Invalid URL provided: {}", url); 314 | return Ok(()); 315 | } 316 | 317 | // Wrap download in error handling to prevent crashes 318 | if let Err(e) = self.perform_download(url.to_string(), bitrate).await { 319 | error!("Download failed: {}", e); 320 | self.download_status = DownloadStatus::Error(e.to_string()); 321 | self.status_message = format!("❌ Download failed: {e}"); 322 | } 323 | 324 | Ok(()) 325 | } 326 | 327 | /// Perform the actual download with proper error isolation 328 | async fn perform_download(&mut self, url: String, bitrate: u32) -> Result<()> { 329 | // Starting download silently 330 | self.download_status = DownloadStatus::Downloading; 331 | self.status_message = format!("🎵 Downloading MP3 at {bitrate}kbps... Please wait"); 332 | 333 | // Clear the input field when download starts 334 | self.input.clear(); 335 | 336 | // Download directly to Downloads folder (no subfolder) 337 | let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string()); 338 | let output_dir = PathBuf::from(home).join("Downloads"); 339 | 340 | // Download using yt-dlp - clean and simple 341 | let file_path = self 342 | .download_mp3(url, output_dir, bitrate) 343 | .await 344 | .map_err(|e| color_eyre::eyre::eyre!("Download failed: {}", e))?; 345 | // Download completed successfully 346 | self.download_status = DownloadStatus::Success(file_path.clone()); 347 | self.status_message = format!("✅ Successfully downloaded: {file_path}"); 348 | 349 | // Add to download history for display - extract just the filename 350 | if let Some(filename) = file_path.strip_prefix("✅ Downloaded: ") { 351 | self.download_history.push(filename.to_string()); 352 | } else { 353 | // Fallback in case format changes 354 | self.download_history.push(file_path.clone()); 355 | } 356 | 357 | Ok(()) 358 | } 359 | 360 | /// Download MP3 using yt-dlp - clean and simple (2025 best practice) 361 | async fn download_mp3( 362 | &self, 363 | url: String, 364 | output_dir: PathBuf, 365 | bitrate: u32, 366 | ) -> Result> { 367 | // Step 1: Get list of existing MP3 files BEFORE download 368 | let existing_mp3s = self.get_mp3_files(&output_dir).await.unwrap_or_default(); 369 | 370 | // Step 2: Do the actual download (back to working logic) 371 | let output_template = output_dir.join("%(title)s.%(ext)s"); 372 | 373 | let mut cmd = tokio::process::Command::new("yt-dlp"); 374 | let bitrate_arg = format!("{bitrate}K"); 375 | let output_arg = output_template.to_string_lossy().to_string(); 376 | cmd.args([ 377 | "--format", 378 | "bestaudio", // Download ONLY audio stream (no video) 379 | "--extract-audio", // Extract to final format 380 | "--audio-format", 381 | "mp3", // Convert to MP3 382 | "--audio-quality", 383 | &bitrate_arg, // Bitrate (128K/256K) 384 | "--output", 385 | &output_arg, // Save to Downloads/[title].mp3 386 | "--no-playlist", // Single video only 387 | "--prefer-ffmpeg", // Use ffmpeg for conversion 388 | "--embed-thumbnail", // Add album art 389 | "--add-metadata", // Add metadata 390 | "--no-warnings", // Suppress warnings 391 | "--quiet", // Minimal output 392 | url.as_str(), // YouTube URL 393 | ]); 394 | 395 | // Completely suppress all output to keep TUI clean 396 | cmd.stdout(Stdio::null()) 397 | .stderr(Stdio::null()) 398 | .stdin(Stdio::null()); 399 | 400 | let output = cmd 401 | .output() 402 | .await 403 | .map_err(|_| "yt-dlp not found. Please install: brew install yt-dlp".to_string())?; 404 | 405 | if !output.status.success() { 406 | return Err( 407 | "Download failed. Check if the YouTube URL is valid and accessible.".into(), 408 | ); 409 | } 410 | 411 | // Give the file system a moment to update 412 | tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; 413 | 414 | // Step 3: Get list of MP3 files AFTER download 415 | let new_mp3s = self.get_mp3_files(&output_dir).await.unwrap_or_default(); 416 | 417 | // Step 4: Find the NEW file (difference between before and after) 418 | let new_file = new_mp3s 419 | .iter() 420 | .find(|file| !existing_mp3s.contains(file)) 421 | .cloned() 422 | .unwrap_or_else(|| { 423 | // If no new file found, try to get the most recently modified MP3 424 | fs::read_dir(&output_dir) 425 | .ok() 426 | .and_then(|entries| { 427 | entries 428 | .filter_map(|e| e.ok()) 429 | .filter(|e| e.path().extension().is_some_and(|ext| ext == "mp3")) 430 | .max_by_key(|e| { 431 | e.metadata() 432 | .and_then(|m| m.modified()) 433 | .unwrap_or(UNIX_EPOCH) 434 | }) 435 | }) 436 | .and_then(|e| e.file_name().into_string().ok()) 437 | .unwrap_or_else(|| "unknown.mp3".to_string()) 438 | }); 439 | 440 | Ok(format!("✅ Downloaded: {new_file}")) 441 | } 442 | 443 | /// Helper function to get all MP3 filenames in a directory 444 | async fn get_mp3_files( 445 | &self, 446 | dir: &PathBuf, 447 | ) -> Result, Box> { 448 | let mut mp3_files = Vec::new(); 449 | 450 | // Check if directory exists 451 | if !dir.exists() { 452 | return Ok(mp3_files); 453 | } 454 | 455 | let mut entries = tokio::fs::read_dir(dir).await?; 456 | 457 | while let Some(entry) = entries.next_entry().await? { 458 | let path = entry.path(); 459 | 460 | // Only process files (not directories) 461 | if path.is_file() { 462 | if let Some(extension) = path.extension() { 463 | if extension == "mp3" { 464 | if let Some(filename) = path.file_name() { 465 | if let Some(filename_str) = filename.to_str() { 466 | // Only add non-empty filenames that actually contain text 467 | if !filename_str.is_empty() && filename_str.len() > 4 { 468 | mp3_files.push(filename_str.to_string()); 469 | } 470 | } 471 | } 472 | } 473 | } 474 | } 475 | } 476 | 477 | Ok(mp3_files) 478 | } 479 | 480 | /// Get the current input value 481 | pub fn input_value(&self) -> &str { 482 | &self.input 483 | } 484 | 485 | /// Check if input field is focused 486 | pub fn is_input_focused(&self) -> bool { 487 | true // Always focused now since it's the only element 488 | } 489 | } 490 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::Result; 2 | use tracing::{error, info}; 3 | // use tracing_subscriber; 4 | 5 | pub mod app; 6 | pub mod ui; 7 | 8 | use app::App; 9 | 10 | #[tokio::main] 11 | async fn main() -> Result<()> { 12 | // Initialize error handling 13 | color_eyre::install()?; 14 | 15 | // Disable logging to keep TUI clean 16 | // tracing_subscriber::fmt::init(); 17 | 18 | info!("Starting DJ CLI"); 19 | 20 | // Initialize terminal 21 | let terminal = ratatui::init(); 22 | 23 | // Run the app 24 | let app_result = App::new().run(terminal).await; 25 | 26 | // Restore terminal 27 | ratatui::restore(); 28 | 29 | if let Err(e) = &app_result { 30 | error!("Application error: {}", e); 31 | } 32 | 33 | app_result 34 | } 35 | -------------------------------------------------------------------------------- /src/ui.rs: -------------------------------------------------------------------------------- 1 | use ratatui::{ 2 | Frame, 3 | layout::{Constraint, Direction, Layout}, 4 | style::{Color, Modifier, Style}, 5 | text::{Line, Span}, 6 | widgets::{Block, Borders, Paragraph, Wrap}, 7 | }; 8 | // Removed ratatui_input for simplicity 9 | 10 | use crate::app::{App, DownloadStatus}; 11 | 12 | /// Render the main UI 13 | pub fn render(frame: &mut Frame, app: &App) { 14 | let area = frame.area(); 15 | 16 | // Create main layout - dynamic constraints based on what needs to be shown 17 | let has_download_activity = matches!(app.download_status, DownloadStatus::Downloading) 18 | || !app.download_history.is_empty(); 19 | 20 | let chunks = Layout::default() 21 | .direction(Direction::Vertical) 22 | .constraints([ 23 | Constraint::Length(8), // Title (6 lines + 2 for borders) 24 | Constraint::Length(1), // Spacing 25 | Constraint::Length(3), // Input box 26 | Constraint::Length(1), // Spacing 27 | Constraint::Length(4), // Instructions 28 | Constraint::Length(if has_download_activity { 4 } else { 0 }), // Download status (conditional) 29 | Constraint::Min(0), // Remaining space 30 | ]) 31 | .split(area); 32 | 33 | // Title - Bright neon cyan (classic terminal green alternative) 34 | let title_text = vec![ 35 | Line::from(vec![Span::styled( 36 | " _____ _ _____ _ _____ ", 37 | Style::default() 38 | .fg(Color::Rgb(0, 255, 0)) 39 | .add_modifier(Modifier::BOLD), 40 | )]), 41 | Line::from(vec![Span::styled( 42 | "| __ \\ | | / ____| | |_ _|", 43 | Style::default() 44 | .fg(Color::Rgb(0, 255, 0)) 45 | .add_modifier(Modifier::BOLD), 46 | )]), 47 | Line::from(vec![Span::styled( 48 | "| | | | | | | | | | | | ", 49 | Style::default() 50 | .fg(Color::Rgb(0, 255, 0)) 51 | .add_modifier(Modifier::BOLD), 52 | )]), 53 | Line::from(vec![Span::styled( 54 | "| | | |_ | | | | | | | | ", 55 | Style::default() 56 | .fg(Color::Rgb(0, 255, 0)) 57 | .add_modifier(Modifier::BOLD), 58 | )]), 59 | Line::from(vec![Span::styled( 60 | "| |__| | |__| | | |____| |____ _| |_ ", 61 | Style::default() 62 | .fg(Color::Rgb(0, 255, 0)) 63 | .add_modifier(Modifier::BOLD), 64 | )]), 65 | Line::from(vec![Span::styled( 66 | "|_____/ \\____/ \\_____|______|_____|", 67 | Style::default() 68 | .fg(Color::Rgb(0, 255, 0)) 69 | .add_modifier(Modifier::BOLD), 70 | )]), 71 | Line::from(vec![Span::styled( 72 | " ", 73 | Style::default() 74 | .fg(Color::Rgb(0, 255, 0)) 75 | .add_modifier(Modifier::BOLD), 76 | )]), 77 | Line::from(vec![Span::styled( 78 | " ", 79 | Style::default() 80 | .fg(Color::Rgb(0, 255, 0)) 81 | .add_modifier(Modifier::BOLD), 82 | )]), 83 | ]; 84 | 85 | let title = Paragraph::new(title_text) 86 | .style( 87 | Style::default() 88 | .fg(Color::Rgb(0, 255, 0)) 89 | .add_modifier(Modifier::BOLD), 90 | ) 91 | .alignment(ratatui::layout::Alignment::Center); 92 | frame.render_widget(title, chunks[0]); 93 | 94 | // Input box - Bright yellow when focused 95 | let input_style = if app.is_input_focused() { 96 | Style::default().fg(Color::Rgb(255, 255, 0)) // Bright yellow 97 | } else { 98 | Style::default().fg(Color::Rgb(255, 255, 255)) // Bright white 99 | }; 100 | 101 | let input_block = Block::default() 102 | .borders(Borders::ALL) 103 | .title("YouTube URL") 104 | .border_style(if app.is_input_focused() { 105 | Style::default().fg(Color::Rgb(255, 255, 0)) // Bright yellow border 106 | } else { 107 | Style::default().fg(Color::Rgb(128, 128, 128)) // Gray 108 | }); 109 | 110 | let input_widget = Paragraph::new(app.input_value()) 111 | .style(input_style) 112 | .block(input_block); 113 | frame.render_widget(input_widget, chunks[2]); 114 | 115 | // Instructions section 116 | let instructions_text = vec![ 117 | Line::from(vec![Span::styled( 118 | "📋 HOW TO USE:", 119 | Style::default() 120 | .fg(Color::Rgb(0, 255, 255)) 121 | .add_modifier(Modifier::BOLD), 122 | )]), 123 | Line::from(vec![ 124 | Span::styled("1. ", Style::default().fg(Color::Rgb(255, 255, 0))), // Bright yellow 125 | Span::raw("Paste URL, press "), 126 | Span::styled( 127 | "Enter", 128 | Style::default() 129 | .fg(Color::Rgb(0, 255, 0)) 130 | .add_modifier(Modifier::BOLD), 131 | ), // Bright green 132 | Span::raw(" to download"), 133 | ]), 134 | Line::from(vec![ 135 | Span::styled("2. ", Style::default().fg(Color::Rgb(255, 255, 0))), // Bright yellow 136 | Span::raw("Press "), 137 | Span::styled( 138 | "F5", 139 | Style::default() 140 | .fg(Color::Rgb(0, 255, 0)) 141 | .add_modifier(Modifier::BOLD), 142 | ), // Bright green 143 | Span::raw(" to clean pasted text"), 144 | ]), 145 | ]; 146 | 147 | let instructions = Paragraph::new(instructions_text) 148 | .style(Style::default().fg(Color::Rgb(255, 255, 255))) // Bright white 149 | .block(Block::default().borders(Borders::ALL).title("How to Use")); 150 | frame.render_widget(instructions, chunks[4]); 151 | 152 | // Download status and history (only when there's activity) 153 | if has_download_activity { 154 | let mut status_lines = Vec::new(); 155 | 156 | // Show current download status if downloading 157 | if let DownloadStatus::Downloading = &app.download_status { 158 | status_lines.push(Line::from(vec![ 159 | Span::styled("🎵 ", Style::default().fg(Color::Rgb(255, 255, 0))), 160 | Span::styled( 161 | "Downloading...", 162 | Style::default() 163 | .fg(Color::Rgb(255, 255, 0)) 164 | .add_modifier(Modifier::BOLD), 165 | ), 166 | ])); 167 | } 168 | 169 | // Show recent downloads (last 2 to keep it compact) 170 | for download in app.download_history.iter().rev().take(2) { 171 | // Wrap long filenames - truncate at 50 chars and add ... 172 | let display_name = if download.len() > 50 { 173 | format!("{}...", &download[..47]) 174 | } else { 175 | download.clone() 176 | }; 177 | 178 | status_lines.push(Line::from(vec![ 179 | Span::styled("✅ ", Style::default().fg(Color::Rgb(0, 255, 0))), 180 | Span::styled(display_name, Style::default().fg(Color::Rgb(0, 255, 0))), 181 | ])); 182 | } 183 | 184 | let status_widget = Paragraph::new(status_lines) 185 | .style(Style::default().fg(Color::Rgb(255, 255, 255))) 186 | .block(Block::default().borders(Borders::ALL).title("Downloads")) 187 | .wrap(Wrap { trim: true }); 188 | 189 | let status_chunk = chunks[5]; 190 | frame.render_widget(status_widget, status_chunk); 191 | } 192 | } 193 | --------------------------------------------------------------------------------