├── .envrc ├── .github └── workflows │ └── build_nix.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE.md ├── README.md ├── default.nix ├── flake.lock ├── flake.nix └── src ├── config.rs ├── main.rs └── tests.rs /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.github/workflows/build_nix.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | name: "Build Nix package on Ubuntu" 3 | 4 | env: 5 | RUSTFLAGS: "-Dwarnings" 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: cachix/install-nix-action@v23 13 | - name: Building package 14 | run: nix build 15 | - name: Get repository name 16 | run: echo "REPO_NAME=${GITHUB_REPOSITORY#*/}" >> $GITHUB_ENV 17 | - name: Get commit hash 18 | run: echo "COMMIT_HASH=${GITHUB_SHA::6}" >> $GITHUB_ENV 19 | - uses: actions/upload-artifact@v3 20 | with: 21 | name: ${{ env.REPO_NAME }}-${{ env.COMMIT_HASH }}-x86_64-linux 22 | path: result/bin/${{ env.REPO_NAME }} 23 | check: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v4 27 | - uses: cachix/install-nix-action@v23 28 | - name: Lint 29 | run: nix develop --command cargo clippy --all-targets --all-features 30 | - name: Test 31 | run: nix develop --command cargo test 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .direnv -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.7.7" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" 25 | dependencies = [ 26 | "getrandom", 27 | "once_cell", 28 | "version_check", 29 | ] 30 | 31 | [[package]] 32 | name = "ahash" 33 | version = "0.8.7" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" 36 | dependencies = [ 37 | "cfg-if", 38 | "once_cell", 39 | "version_check", 40 | "zerocopy", 41 | ] 42 | 43 | [[package]] 44 | name = "allocator-api2" 45 | version = "0.2.16" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" 48 | 49 | [[package]] 50 | name = "arboard" 51 | version = "3.3.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "aafb29b107435aa276664c1db8954ac27a6e105cdad3c88287a199eb0e313c08" 54 | dependencies = [ 55 | "clipboard-win", 56 | "core-graphics", 57 | "image", 58 | "log", 59 | "objc", 60 | "objc-foundation", 61 | "objc_id", 62 | "parking_lot", 63 | "thiserror", 64 | "winapi", 65 | "wl-clipboard-rs", 66 | "x11rb", 67 | ] 68 | 69 | [[package]] 70 | name = "autocfg" 71 | version = "1.1.0" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 74 | 75 | [[package]] 76 | name = "backtrace" 77 | version = "0.3.69" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" 80 | dependencies = [ 81 | "addr2line", 82 | "cc", 83 | "cfg-if", 84 | "libc", 85 | "miniz_oxide", 86 | "object", 87 | "rustc-demangle", 88 | ] 89 | 90 | [[package]] 91 | name = "backtrace-ext" 92 | version = "0.2.1" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" 95 | dependencies = [ 96 | "backtrace", 97 | ] 98 | 99 | [[package]] 100 | name = "base64" 101 | version = "0.21.7" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 104 | 105 | [[package]] 106 | name = "bitflags" 107 | version = "1.3.2" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 110 | 111 | [[package]] 112 | name = "bitflags" 113 | version = "2.4.2" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" 116 | 117 | [[package]] 118 | name = "block" 119 | version = "0.1.6" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" 122 | 123 | [[package]] 124 | name = "bytecount" 125 | version = "0.6.7" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" 128 | 129 | [[package]] 130 | name = "bytemuck" 131 | version = "1.14.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" 134 | 135 | [[package]] 136 | name = "byteorder" 137 | version = "1.5.0" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 140 | 141 | [[package]] 142 | name = "cc" 143 | version = "1.0.83" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 146 | dependencies = [ 147 | "libc", 148 | ] 149 | 150 | [[package]] 151 | name = "cfg-if" 152 | version = "1.0.0" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 155 | 156 | [[package]] 157 | name = "chumsky" 158 | version = "0.9.3" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9" 161 | dependencies = [ 162 | "hashbrown 0.14.3", 163 | ] 164 | 165 | [[package]] 166 | name = "clipboard-win" 167 | version = "4.5.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" 170 | dependencies = [ 171 | "error-code", 172 | "str-buf", 173 | "winapi", 174 | ] 175 | 176 | [[package]] 177 | name = "color_quant" 178 | version = "1.1.0" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" 181 | 182 | [[package]] 183 | name = "core-foundation" 184 | version = "0.9.4" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 187 | dependencies = [ 188 | "core-foundation-sys", 189 | "libc", 190 | ] 191 | 192 | [[package]] 193 | name = "core-foundation-sys" 194 | version = "0.8.6" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 197 | 198 | [[package]] 199 | name = "core-graphics" 200 | version = "0.22.3" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" 203 | dependencies = [ 204 | "bitflags 1.3.2", 205 | "core-foundation", 206 | "core-graphics-types", 207 | "foreign-types", 208 | "libc", 209 | ] 210 | 211 | [[package]] 212 | name = "core-graphics-types" 213 | version = "0.1.3" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" 216 | dependencies = [ 217 | "bitflags 1.3.2", 218 | "core-foundation", 219 | "libc", 220 | ] 221 | 222 | [[package]] 223 | name = "crc32fast" 224 | version = "1.3.2" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 227 | dependencies = [ 228 | "cfg-if", 229 | ] 230 | 231 | [[package]] 232 | name = "derive-new" 233 | version = "0.5.9" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" 236 | dependencies = [ 237 | "proc-macro2", 238 | "quote", 239 | "syn 1.0.109", 240 | ] 241 | 242 | [[package]] 243 | name = "diff" 244 | version = "0.1.13" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" 247 | 248 | [[package]] 249 | name = "dlib" 250 | version = "0.5.2" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" 253 | dependencies = [ 254 | "libloading", 255 | ] 256 | 257 | [[package]] 258 | name = "downcast-rs" 259 | version = "1.2.0" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" 262 | 263 | [[package]] 264 | name = "equivalent" 265 | version = "1.0.1" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 268 | 269 | [[package]] 270 | name = "errno" 271 | version = "0.3.8" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 274 | dependencies = [ 275 | "libc", 276 | "windows-sys 0.52.0", 277 | ] 278 | 279 | [[package]] 280 | name = "error-code" 281 | version = "2.3.1" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" 284 | dependencies = [ 285 | "libc", 286 | "str-buf", 287 | ] 288 | 289 | [[package]] 290 | name = "fastrand" 291 | version = "2.0.1" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" 294 | 295 | [[package]] 296 | name = "fdeflate" 297 | version = "0.3.4" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" 300 | dependencies = [ 301 | "simd-adler32", 302 | ] 303 | 304 | [[package]] 305 | name = "fixedbitset" 306 | version = "0.4.2" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" 309 | 310 | [[package]] 311 | name = "flate2" 312 | version = "1.0.28" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" 315 | dependencies = [ 316 | "crc32fast", 317 | "miniz_oxide", 318 | ] 319 | 320 | [[package]] 321 | name = "fnv" 322 | version = "1.0.7" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 325 | 326 | [[package]] 327 | name = "foreign-types" 328 | version = "0.3.2" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 331 | dependencies = [ 332 | "foreign-types-shared", 333 | ] 334 | 335 | [[package]] 336 | name = "foreign-types-shared" 337 | version = "0.1.1" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 340 | 341 | [[package]] 342 | name = "form_urlencoded" 343 | version = "1.2.1" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 346 | dependencies = [ 347 | "percent-encoding", 348 | ] 349 | 350 | [[package]] 351 | name = "gethostname" 352 | version = "0.3.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177" 355 | dependencies = [ 356 | "libc", 357 | "winapi", 358 | ] 359 | 360 | [[package]] 361 | name = "getrandom" 362 | version = "0.2.12" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" 365 | dependencies = [ 366 | "cfg-if", 367 | "libc", 368 | "wasi", 369 | ] 370 | 371 | [[package]] 372 | name = "gimli" 373 | version = "0.28.1" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 376 | 377 | [[package]] 378 | name = "hashbrown" 379 | version = "0.12.3" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 382 | dependencies = [ 383 | "ahash 0.7.7", 384 | ] 385 | 386 | [[package]] 387 | name = "hashbrown" 388 | version = "0.14.3" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 391 | dependencies = [ 392 | "ahash 0.8.7", 393 | "allocator-api2", 394 | ] 395 | 396 | [[package]] 397 | name = "heck" 398 | version = "0.4.1" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 401 | dependencies = [ 402 | "unicode-segmentation", 403 | ] 404 | 405 | [[package]] 406 | name = "hermit-abi" 407 | version = "0.3.4" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" 410 | 411 | [[package]] 412 | name = "idna" 413 | version = "0.5.0" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 416 | dependencies = [ 417 | "unicode-bidi", 418 | "unicode-normalization", 419 | ] 420 | 421 | [[package]] 422 | name = "image" 423 | version = "0.24.8" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "034bbe799d1909622a74d1193aa50147769440040ff36cb2baa947609b0a4e23" 426 | dependencies = [ 427 | "bytemuck", 428 | "byteorder", 429 | "color_quant", 430 | "num-traits", 431 | "png", 432 | "tiff", 433 | ] 434 | 435 | [[package]] 436 | name = "indexmap" 437 | version = "2.1.0" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" 440 | dependencies = [ 441 | "equivalent", 442 | "hashbrown 0.14.3", 443 | ] 444 | 445 | [[package]] 446 | name = "is-terminal" 447 | version = "0.4.10" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" 450 | dependencies = [ 451 | "hermit-abi", 452 | "rustix", 453 | "windows-sys 0.52.0", 454 | ] 455 | 456 | [[package]] 457 | name = "is_ci" 458 | version = "1.1.1" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" 461 | 462 | [[package]] 463 | name = "jpeg-decoder" 464 | version = "0.3.1" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" 467 | 468 | [[package]] 469 | name = "knuffel" 470 | version = "3.2.0" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "04bee6ddc6071011314b1ce4f7705fef6c009401dba4fd22cb0009db6a177413" 473 | dependencies = [ 474 | "base64", 475 | "chumsky", 476 | "knuffel-derive", 477 | "miette", 478 | "thiserror", 479 | "unicode-width", 480 | ] 481 | 482 | [[package]] 483 | name = "knuffel-derive" 484 | version = "3.2.0" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "91977f56c49cfb961e3d840e2e7c6e4a56bde7283898cf606861f1421348283d" 487 | dependencies = [ 488 | "heck", 489 | "proc-macro-error", 490 | "proc-macro2", 491 | "quote", 492 | "syn 1.0.109", 493 | ] 494 | 495 | [[package]] 496 | name = "lazy_static" 497 | version = "1.4.0" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 500 | 501 | [[package]] 502 | name = "libc" 503 | version = "0.2.152" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" 506 | 507 | [[package]] 508 | name = "libloading" 509 | version = "0.8.1" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" 512 | dependencies = [ 513 | "cfg-if", 514 | "windows-sys 0.48.0", 515 | ] 516 | 517 | [[package]] 518 | name = "linux-raw-sys" 519 | version = "0.4.13" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" 522 | 523 | [[package]] 524 | name = "lock_api" 525 | version = "0.4.11" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" 528 | dependencies = [ 529 | "autocfg", 530 | "scopeguard", 531 | ] 532 | 533 | [[package]] 534 | name = "log" 535 | version = "0.4.20" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 538 | 539 | [[package]] 540 | name = "lru" 541 | version = "0.7.8" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" 544 | dependencies = [ 545 | "hashbrown 0.12.3", 546 | ] 547 | 548 | [[package]] 549 | name = "malloc_buf" 550 | version = "0.0.6" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" 553 | dependencies = [ 554 | "libc", 555 | ] 556 | 557 | [[package]] 558 | name = "memchr" 559 | version = "2.7.1" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" 562 | 563 | [[package]] 564 | name = "memoffset" 565 | version = "0.7.1" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" 568 | dependencies = [ 569 | "autocfg", 570 | ] 571 | 572 | [[package]] 573 | name = "memoize" 574 | version = "0.4.2" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "5df4051db13d0816cf23196d3baa216385ae099339f5d0645a8d9ff2305e82b8" 577 | dependencies = [ 578 | "lazy_static", 579 | "lru", 580 | "memoize-inner", 581 | ] 582 | 583 | [[package]] 584 | name = "memoize-inner" 585 | version = "0.4.3" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "27bdece7e91f0d1e33df7b46ec187a93ea0d4e642113a1039ac8bfdd4a3273ac" 588 | dependencies = [ 589 | "lazy_static", 590 | "proc-macro2", 591 | "quote", 592 | "syn 1.0.109", 593 | ] 594 | 595 | [[package]] 596 | name = "miette" 597 | version = "5.10.0" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" 600 | dependencies = [ 601 | "backtrace", 602 | "backtrace-ext", 603 | "is-terminal", 604 | "miette-derive", 605 | "once_cell", 606 | "owo-colors", 607 | "supports-color", 608 | "supports-hyperlinks", 609 | "supports-unicode", 610 | "terminal_size", 611 | "textwrap", 612 | "thiserror", 613 | "unicode-width", 614 | ] 615 | 616 | [[package]] 617 | name = "miette-derive" 618 | version = "5.10.0" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" 621 | dependencies = [ 622 | "proc-macro2", 623 | "quote", 624 | "syn 2.0.48", 625 | ] 626 | 627 | [[package]] 628 | name = "minimal-lexical" 629 | version = "0.2.1" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 632 | 633 | [[package]] 634 | name = "miniz_oxide" 635 | version = "0.7.1" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 638 | dependencies = [ 639 | "adler", 640 | "simd-adler32", 641 | ] 642 | 643 | [[package]] 644 | name = "nix" 645 | version = "0.26.4" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" 648 | dependencies = [ 649 | "bitflags 1.3.2", 650 | "cfg-if", 651 | "libc", 652 | "memoffset", 653 | "pin-utils", 654 | ] 655 | 656 | [[package]] 657 | name = "nom" 658 | version = "7.1.3" 659 | source = "registry+https://github.com/rust-lang/crates.io-index" 660 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 661 | dependencies = [ 662 | "memchr", 663 | "minimal-lexical", 664 | ] 665 | 666 | [[package]] 667 | name = "num-traits" 668 | version = "0.2.17" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" 671 | dependencies = [ 672 | "autocfg", 673 | ] 674 | 675 | [[package]] 676 | name = "objc" 677 | version = "0.2.7" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" 680 | dependencies = [ 681 | "malloc_buf", 682 | ] 683 | 684 | [[package]] 685 | name = "objc-foundation" 686 | version = "0.1.1" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" 689 | dependencies = [ 690 | "block", 691 | "objc", 692 | "objc_id", 693 | ] 694 | 695 | [[package]] 696 | name = "objc_id" 697 | version = "0.1.1" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" 700 | dependencies = [ 701 | "objc", 702 | ] 703 | 704 | [[package]] 705 | name = "object" 706 | version = "0.32.2" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" 709 | dependencies = [ 710 | "memchr", 711 | ] 712 | 713 | [[package]] 714 | name = "once_cell" 715 | version = "1.19.0" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 718 | 719 | [[package]] 720 | name = "os_pipe" 721 | version = "1.1.5" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9" 724 | dependencies = [ 725 | "libc", 726 | "windows-sys 0.52.0", 727 | ] 728 | 729 | [[package]] 730 | name = "owo-colors" 731 | version = "3.5.0" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" 734 | 735 | [[package]] 736 | name = "parking_lot" 737 | version = "0.12.1" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 740 | dependencies = [ 741 | "lock_api", 742 | "parking_lot_core", 743 | ] 744 | 745 | [[package]] 746 | name = "parking_lot_core" 747 | version = "0.9.9" 748 | source = "registry+https://github.com/rust-lang/crates.io-index" 749 | checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" 750 | dependencies = [ 751 | "cfg-if", 752 | "libc", 753 | "redox_syscall", 754 | "smallvec", 755 | "windows-targets 0.48.5", 756 | ] 757 | 758 | [[package]] 759 | name = "percent-encoding" 760 | version = "2.3.1" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 763 | 764 | [[package]] 765 | name = "petgraph" 766 | version = "0.6.4" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" 769 | dependencies = [ 770 | "fixedbitset", 771 | "indexmap", 772 | ] 773 | 774 | [[package]] 775 | name = "pin-utils" 776 | version = "0.1.0" 777 | source = "registry+https://github.com/rust-lang/crates.io-index" 778 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 779 | 780 | [[package]] 781 | name = "pkg-config" 782 | version = "0.3.29" 783 | source = "registry+https://github.com/rust-lang/crates.io-index" 784 | checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" 785 | 786 | [[package]] 787 | name = "png" 788 | version = "0.17.11" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "1f6c3c3e617595665b8ea2ff95a86066be38fb121ff920a9c0eb282abcd1da5a" 791 | dependencies = [ 792 | "bitflags 1.3.2", 793 | "crc32fast", 794 | "fdeflate", 795 | "flate2", 796 | "miniz_oxide", 797 | ] 798 | 799 | [[package]] 800 | name = "pretty_assertions" 801 | version = "1.4.0" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" 804 | dependencies = [ 805 | "diff", 806 | "yansi", 807 | ] 808 | 809 | [[package]] 810 | name = "proc-macro-error" 811 | version = "1.0.4" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 814 | dependencies = [ 815 | "proc-macro-error-attr", 816 | "proc-macro2", 817 | "quote", 818 | "syn 1.0.109", 819 | "version_check", 820 | ] 821 | 822 | [[package]] 823 | name = "proc-macro-error-attr" 824 | version = "1.0.4" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 827 | dependencies = [ 828 | "proc-macro2", 829 | "quote", 830 | "version_check", 831 | ] 832 | 833 | [[package]] 834 | name = "proc-macro2" 835 | version = "1.0.78" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" 838 | dependencies = [ 839 | "unicode-ident", 840 | ] 841 | 842 | [[package]] 843 | name = "quick-xml" 844 | version = "0.30.0" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" 847 | dependencies = [ 848 | "memchr", 849 | ] 850 | 851 | [[package]] 852 | name = "quote" 853 | version = "1.0.35" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 856 | dependencies = [ 857 | "proc-macro2", 858 | ] 859 | 860 | [[package]] 861 | name = "redox_syscall" 862 | version = "0.4.1" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" 865 | dependencies = [ 866 | "bitflags 1.3.2", 867 | ] 868 | 869 | [[package]] 870 | name = "rustc-demangle" 871 | version = "0.1.23" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 874 | 875 | [[package]] 876 | name = "rustix" 877 | version = "0.38.30" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" 880 | dependencies = [ 881 | "bitflags 2.4.2", 882 | "errno", 883 | "libc", 884 | "linux-raw-sys", 885 | "windows-sys 0.52.0", 886 | ] 887 | 888 | [[package]] 889 | name = "scoped-tls" 890 | version = "1.0.1" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 893 | 894 | [[package]] 895 | name = "scopeguard" 896 | version = "1.2.0" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 899 | 900 | [[package]] 901 | name = "simd-adler32" 902 | version = "0.3.7" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" 905 | 906 | [[package]] 907 | name = "smallvec" 908 | version = "1.13.1" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" 911 | 912 | [[package]] 913 | name = "smawk" 914 | version = "0.3.2" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" 917 | 918 | [[package]] 919 | name = "str-buf" 920 | version = "1.0.6" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" 923 | 924 | [[package]] 925 | name = "supports-color" 926 | version = "2.1.0" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" 929 | dependencies = [ 930 | "is-terminal", 931 | "is_ci", 932 | ] 933 | 934 | [[package]] 935 | name = "supports-hyperlinks" 936 | version = "2.1.0" 937 | source = "registry+https://github.com/rust-lang/crates.io-index" 938 | checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d" 939 | dependencies = [ 940 | "is-terminal", 941 | ] 942 | 943 | [[package]] 944 | name = "supports-unicode" 945 | version = "2.1.0" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "f850c19edd184a205e883199a261ed44471c81e39bd95b1357f5febbef00e77a" 948 | dependencies = [ 949 | "is-terminal", 950 | ] 951 | 952 | [[package]] 953 | name = "syn" 954 | version = "1.0.109" 955 | source = "registry+https://github.com/rust-lang/crates.io-index" 956 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 957 | dependencies = [ 958 | "proc-macro2", 959 | "quote", 960 | "unicode-ident", 961 | ] 962 | 963 | [[package]] 964 | name = "syn" 965 | version = "2.0.48" 966 | source = "registry+https://github.com/rust-lang/crates.io-index" 967 | checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" 968 | dependencies = [ 969 | "proc-macro2", 970 | "quote", 971 | "unicode-ident", 972 | ] 973 | 974 | [[package]] 975 | name = "tempfile" 976 | version = "3.9.0" 977 | source = "registry+https://github.com/rust-lang/crates.io-index" 978 | checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" 979 | dependencies = [ 980 | "cfg-if", 981 | "fastrand", 982 | "redox_syscall", 983 | "rustix", 984 | "windows-sys 0.52.0", 985 | ] 986 | 987 | [[package]] 988 | name = "terminal_size" 989 | version = "0.1.17" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" 992 | dependencies = [ 993 | "libc", 994 | "winapi", 995 | ] 996 | 997 | [[package]] 998 | name = "textwrap" 999 | version = "0.15.2" 1000 | source = "registry+https://github.com/rust-lang/crates.io-index" 1001 | checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" 1002 | dependencies = [ 1003 | "smawk", 1004 | "unicode-linebreak", 1005 | "unicode-width", 1006 | ] 1007 | 1008 | [[package]] 1009 | name = "thiserror" 1010 | version = "1.0.56" 1011 | source = "registry+https://github.com/rust-lang/crates.io-index" 1012 | checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" 1013 | dependencies = [ 1014 | "thiserror-impl", 1015 | ] 1016 | 1017 | [[package]] 1018 | name = "thiserror-impl" 1019 | version = "1.0.56" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" 1022 | dependencies = [ 1023 | "proc-macro2", 1024 | "quote", 1025 | "syn 2.0.48", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "tiff" 1030 | version = "0.9.1" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" 1033 | dependencies = [ 1034 | "flate2", 1035 | "jpeg-decoder", 1036 | "weezl", 1037 | ] 1038 | 1039 | [[package]] 1040 | name = "tinyvec" 1041 | version = "1.6.0" 1042 | source = "registry+https://github.com/rust-lang/crates.io-index" 1043 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1044 | dependencies = [ 1045 | "tinyvec_macros", 1046 | ] 1047 | 1048 | [[package]] 1049 | name = "tinyvec_macros" 1050 | version = "0.1.1" 1051 | source = "registry+https://github.com/rust-lang/crates.io-index" 1052 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1053 | 1054 | [[package]] 1055 | name = "tree_magic_mini" 1056 | version = "3.0.3" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "91adfd0607cacf6e4babdb870e9bec4037c1c4b151cfd279ccefc5e0c7feaa6d" 1059 | dependencies = [ 1060 | "bytecount", 1061 | "fnv", 1062 | "lazy_static", 1063 | "nom", 1064 | "once_cell", 1065 | "petgraph", 1066 | ] 1067 | 1068 | [[package]] 1069 | name = "unicode-bidi" 1070 | version = "0.3.15" 1071 | source = "registry+https://github.com/rust-lang/crates.io-index" 1072 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 1073 | 1074 | [[package]] 1075 | name = "unicode-ident" 1076 | version = "1.0.12" 1077 | source = "registry+https://github.com/rust-lang/crates.io-index" 1078 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1079 | 1080 | [[package]] 1081 | name = "unicode-linebreak" 1082 | version = "0.1.5" 1083 | source = "registry+https://github.com/rust-lang/crates.io-index" 1084 | checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" 1085 | 1086 | [[package]] 1087 | name = "unicode-normalization" 1088 | version = "0.1.22" 1089 | source = "registry+https://github.com/rust-lang/crates.io-index" 1090 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1091 | dependencies = [ 1092 | "tinyvec", 1093 | ] 1094 | 1095 | [[package]] 1096 | name = "unicode-segmentation" 1097 | version = "1.10.1" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" 1100 | 1101 | [[package]] 1102 | name = "unicode-width" 1103 | version = "0.1.11" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" 1106 | 1107 | [[package]] 1108 | name = "url" 1109 | version = "2.5.0" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" 1112 | dependencies = [ 1113 | "form_urlencoded", 1114 | "idna", 1115 | "percent-encoding", 1116 | ] 1117 | 1118 | [[package]] 1119 | name = "url-eater" 1120 | version = "0.2.0" 1121 | dependencies = [ 1122 | "arboard", 1123 | "knuffel", 1124 | "memoize", 1125 | "miette", 1126 | "pretty_assertions", 1127 | "url", 1128 | "wildmatch", 1129 | ] 1130 | 1131 | [[package]] 1132 | name = "version_check" 1133 | version = "0.9.4" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1136 | 1137 | [[package]] 1138 | name = "wasi" 1139 | version = "0.11.0+wasi-snapshot-preview1" 1140 | source = "registry+https://github.com/rust-lang/crates.io-index" 1141 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1142 | 1143 | [[package]] 1144 | name = "wayland-backend" 1145 | version = "0.3.2" 1146 | source = "registry+https://github.com/rust-lang/crates.io-index" 1147 | checksum = "19152ddd73f45f024ed4534d9ca2594e0ef252c1847695255dae47f34df9fbe4" 1148 | dependencies = [ 1149 | "cc", 1150 | "downcast-rs", 1151 | "nix", 1152 | "scoped-tls", 1153 | "smallvec", 1154 | "wayland-sys", 1155 | ] 1156 | 1157 | [[package]] 1158 | name = "wayland-client" 1159 | version = "0.31.1" 1160 | source = "registry+https://github.com/rust-lang/crates.io-index" 1161 | checksum = "1ca7d52347346f5473bf2f56705f360e8440873052e575e55890c4fa57843ed3" 1162 | dependencies = [ 1163 | "bitflags 2.4.2", 1164 | "nix", 1165 | "wayland-backend", 1166 | "wayland-scanner", 1167 | ] 1168 | 1169 | [[package]] 1170 | name = "wayland-protocols" 1171 | version = "0.31.0" 1172 | source = "registry+https://github.com/rust-lang/crates.io-index" 1173 | checksum = "e253d7107ba913923dc253967f35e8561a3c65f914543e46843c88ddd729e21c" 1174 | dependencies = [ 1175 | "bitflags 2.4.2", 1176 | "wayland-backend", 1177 | "wayland-client", 1178 | "wayland-scanner", 1179 | ] 1180 | 1181 | [[package]] 1182 | name = "wayland-protocols-wlr" 1183 | version = "0.2.0" 1184 | source = "registry+https://github.com/rust-lang/crates.io-index" 1185 | checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" 1186 | dependencies = [ 1187 | "bitflags 2.4.2", 1188 | "wayland-backend", 1189 | "wayland-client", 1190 | "wayland-protocols", 1191 | "wayland-scanner", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "wayland-scanner" 1196 | version = "0.31.0" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "fb8e28403665c9f9513202b7e1ed71ec56fde5c107816843fb14057910b2c09c" 1199 | dependencies = [ 1200 | "proc-macro2", 1201 | "quick-xml", 1202 | "quote", 1203 | ] 1204 | 1205 | [[package]] 1206 | name = "wayland-sys" 1207 | version = "0.31.1" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" 1210 | dependencies = [ 1211 | "dlib", 1212 | "log", 1213 | "pkg-config", 1214 | ] 1215 | 1216 | [[package]] 1217 | name = "weezl" 1218 | version = "0.1.8" 1219 | source = "registry+https://github.com/rust-lang/crates.io-index" 1220 | checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" 1221 | 1222 | [[package]] 1223 | name = "wildmatch" 1224 | version = "2.3.0" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "495ec47bf3c1345005f40724f0269362c8556cbc43aed0526ed44cae1d35fceb" 1227 | 1228 | [[package]] 1229 | name = "winapi" 1230 | version = "0.3.9" 1231 | source = "registry+https://github.com/rust-lang/crates.io-index" 1232 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1233 | dependencies = [ 1234 | "winapi-i686-pc-windows-gnu", 1235 | "winapi-x86_64-pc-windows-gnu", 1236 | ] 1237 | 1238 | [[package]] 1239 | name = "winapi-i686-pc-windows-gnu" 1240 | version = "0.4.0" 1241 | source = "registry+https://github.com/rust-lang/crates.io-index" 1242 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1243 | 1244 | [[package]] 1245 | name = "winapi-wsapoll" 1246 | version = "0.1.1" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" 1249 | dependencies = [ 1250 | "winapi", 1251 | ] 1252 | 1253 | [[package]] 1254 | name = "winapi-x86_64-pc-windows-gnu" 1255 | version = "0.4.0" 1256 | source = "registry+https://github.com/rust-lang/crates.io-index" 1257 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1258 | 1259 | [[package]] 1260 | name = "windows-sys" 1261 | version = "0.48.0" 1262 | source = "registry+https://github.com/rust-lang/crates.io-index" 1263 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1264 | dependencies = [ 1265 | "windows-targets 0.48.5", 1266 | ] 1267 | 1268 | [[package]] 1269 | name = "windows-sys" 1270 | version = "0.52.0" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1273 | dependencies = [ 1274 | "windows-targets 0.52.0", 1275 | ] 1276 | 1277 | [[package]] 1278 | name = "windows-targets" 1279 | version = "0.48.5" 1280 | source = "registry+https://github.com/rust-lang/crates.io-index" 1281 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1282 | dependencies = [ 1283 | "windows_aarch64_gnullvm 0.48.5", 1284 | "windows_aarch64_msvc 0.48.5", 1285 | "windows_i686_gnu 0.48.5", 1286 | "windows_i686_msvc 0.48.5", 1287 | "windows_x86_64_gnu 0.48.5", 1288 | "windows_x86_64_gnullvm 0.48.5", 1289 | "windows_x86_64_msvc 0.48.5", 1290 | ] 1291 | 1292 | [[package]] 1293 | name = "windows-targets" 1294 | version = "0.52.0" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" 1297 | dependencies = [ 1298 | "windows_aarch64_gnullvm 0.52.0", 1299 | "windows_aarch64_msvc 0.52.0", 1300 | "windows_i686_gnu 0.52.0", 1301 | "windows_i686_msvc 0.52.0", 1302 | "windows_x86_64_gnu 0.52.0", 1303 | "windows_x86_64_gnullvm 0.52.0", 1304 | "windows_x86_64_msvc 0.52.0", 1305 | ] 1306 | 1307 | [[package]] 1308 | name = "windows_aarch64_gnullvm" 1309 | version = "0.48.5" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1312 | 1313 | [[package]] 1314 | name = "windows_aarch64_gnullvm" 1315 | version = "0.52.0" 1316 | source = "registry+https://github.com/rust-lang/crates.io-index" 1317 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" 1318 | 1319 | [[package]] 1320 | name = "windows_aarch64_msvc" 1321 | version = "0.48.5" 1322 | source = "registry+https://github.com/rust-lang/crates.io-index" 1323 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1324 | 1325 | [[package]] 1326 | name = "windows_aarch64_msvc" 1327 | version = "0.52.0" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" 1330 | 1331 | [[package]] 1332 | name = "windows_i686_gnu" 1333 | version = "0.48.5" 1334 | source = "registry+https://github.com/rust-lang/crates.io-index" 1335 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1336 | 1337 | [[package]] 1338 | name = "windows_i686_gnu" 1339 | version = "0.52.0" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" 1342 | 1343 | [[package]] 1344 | name = "windows_i686_msvc" 1345 | version = "0.48.5" 1346 | source = "registry+https://github.com/rust-lang/crates.io-index" 1347 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1348 | 1349 | [[package]] 1350 | name = "windows_i686_msvc" 1351 | version = "0.52.0" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" 1354 | 1355 | [[package]] 1356 | name = "windows_x86_64_gnu" 1357 | version = "0.48.5" 1358 | source = "registry+https://github.com/rust-lang/crates.io-index" 1359 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1360 | 1361 | [[package]] 1362 | name = "windows_x86_64_gnu" 1363 | version = "0.52.0" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" 1366 | 1367 | [[package]] 1368 | name = "windows_x86_64_gnullvm" 1369 | version = "0.48.5" 1370 | source = "registry+https://github.com/rust-lang/crates.io-index" 1371 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1372 | 1373 | [[package]] 1374 | name = "windows_x86_64_gnullvm" 1375 | version = "0.52.0" 1376 | source = "registry+https://github.com/rust-lang/crates.io-index" 1377 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" 1378 | 1379 | [[package]] 1380 | name = "windows_x86_64_msvc" 1381 | version = "0.48.5" 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" 1383 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1384 | 1385 | [[package]] 1386 | name = "windows_x86_64_msvc" 1387 | version = "0.52.0" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" 1390 | 1391 | [[package]] 1392 | name = "wl-clipboard-rs" 1393 | version = "0.8.0" 1394 | source = "registry+https://github.com/rust-lang/crates.io-index" 1395 | checksum = "57af79e973eadf08627115c73847392e6b766856ab8e3844a59245354b23d2fa" 1396 | dependencies = [ 1397 | "derive-new", 1398 | "libc", 1399 | "log", 1400 | "nix", 1401 | "os_pipe", 1402 | "tempfile", 1403 | "thiserror", 1404 | "tree_magic_mini", 1405 | "wayland-backend", 1406 | "wayland-client", 1407 | "wayland-protocols", 1408 | "wayland-protocols-wlr", 1409 | ] 1410 | 1411 | [[package]] 1412 | name = "x11rb" 1413 | version = "0.12.0" 1414 | source = "registry+https://github.com/rust-lang/crates.io-index" 1415 | checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a" 1416 | dependencies = [ 1417 | "gethostname", 1418 | "nix", 1419 | "winapi", 1420 | "winapi-wsapoll", 1421 | "x11rb-protocol", 1422 | ] 1423 | 1424 | [[package]] 1425 | name = "x11rb-protocol" 1426 | version = "0.12.0" 1427 | source = "registry+https://github.com/rust-lang/crates.io-index" 1428 | checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc" 1429 | dependencies = [ 1430 | "nix", 1431 | ] 1432 | 1433 | [[package]] 1434 | name = "yansi" 1435 | version = "0.5.1" 1436 | source = "registry+https://github.com/rust-lang/crates.io-index" 1437 | checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" 1438 | 1439 | [[package]] 1440 | name = "zerocopy" 1441 | version = "0.7.32" 1442 | source = "registry+https://github.com/rust-lang/crates.io-index" 1443 | checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" 1444 | dependencies = [ 1445 | "zerocopy-derive", 1446 | ] 1447 | 1448 | [[package]] 1449 | name = "zerocopy-derive" 1450 | version = "0.7.32" 1451 | source = "registry+https://github.com/rust-lang/crates.io-index" 1452 | checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" 1453 | dependencies = [ 1454 | "proc-macro2", 1455 | "quote", 1456 | "syn 2.0.48", 1457 | ] 1458 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "url-eater" 3 | version = "0.2.0" 4 | edition = "2021" 5 | authors = ["Agatha V. Lovelace "] 6 | description = "Strip unneeded parameters from URLs copied to clipboard" 7 | license = "NVPLv7+" 8 | rust-version = "1.66.1" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | arboard = { version = "3.3.0", features = ["wayland-data-control"] } 14 | knuffel = "3.0.0" 15 | memoize = { version = "0.4.0", features = ["full"] } 16 | miette = { version = "5.7.0", features = ["fancy"] } 17 | url = "2.5.0" 18 | wildmatch = "2.1.1" 19 | 20 | [dev-dependencies] 21 | pretty_assertions = "1.4.0" 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS 2 | COOPERATIVE NON-VIOLENT PUBLIC LICENSE (\"LICENSE\"). THE WORK IS 3 | PROTECTED BY COPYRIGHT AND ALL OTHER APPLICABLE LAWS. ANY USE OF THE 4 | WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS 5 | PROHIBITED. BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED IN THIS 6 | LICENSE, YOU AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE 7 | EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR 8 | GRANTS YOU THE RIGHTS CONTAINED HERE IN AS CONSIDERATION FOR ACCEPTING 9 | THE TERMS AND CONDITIONS OF THIS LICENSE AND FOR AGREEING TO BE BOUND BY 10 | THE TERMS AND CONDITIONS OF THIS LICENSE. 11 | 12 | # Definitions 13 | 14 | An Act of War is any action of one country against any group either with 15 | an intention to provoke a conflict or an action that occurs during a 16 | declared war or during armed conflict between military forces of any 17 | origin. This includes but is not limited to enforcing sanctions or 18 | sieges, supplying armed forces, or profiting from the manufacture of 19 | tools or weaponry used in military conflict. 20 | 21 | An Adaptation is a work based upon the Work, or upon the Work and other 22 | pre-existing works, such as a translation, adaptation, derivative work, 23 | arrangement of music or other alterations of a literary or artistic 24 | work, or phonogram or performance and includes cinematographic 25 | adaptations or any other form in which the Work may be recast, 26 | transformed, or adapted including in any form recognizably derived from 27 | the original, except that a work that constitutes a Collection will not 28 | be considered an Adaptation for the purpose of this License. For the 29 | avoidance of doubt, where the Work is a musical work, performance or 30 | phonogram, the synchronization of the Work in timed-relation with a 31 | moving image (\"synching\") will be considered an Adaptation for the 32 | purpose of this License. In addition, where the Work is designed to 33 | output a neural network the output of the neural network will be 34 | considered an Adaptation for the purpose of this license. 35 | 36 | Bodily Harm is any physical hurt or injury to a person that interferes 37 | with the health or comfort of the person and that is more than merely 38 | transient or trifling in nature. 39 | 40 | Distribute is to make available to the public the original and copies of 41 | the Work or Adaptation, as appropriate, through sale, gift or any other 42 | transfer of possession or ownership. 43 | 44 | Incarceration is Confinement in a jail, prison, or any other place where 45 | individuals of any kind are held against either their will or (if their 46 | will cannot be determined) the will of their legal guardian or 47 | guardians. In the case of a conflict between the will of the individual 48 | and the will of their legal guardian or guardians, the will of the 49 | individual will take precedence. 50 | 51 | Licensor is The individual, individuals, entity, or entities that 52 | offer(s) the Work under the terms of this License 53 | 54 | Original Author is in the case of a literary or artistic work, the 55 | individual, individuals, entity or entities who created the Work or if 56 | no individual or entity can be identified, the publisher; and in 57 | addition 58 | 59 | - in the case of a performance the actors, singers, musicians, 60 | dancers, and other persons who act, sing, deliver, declaim, play in, 61 | interpret or otherwise perform literary or artistic works or 62 | expressions of folklore; 63 | 64 | - in the case of a phonogram the producer being the person or legal 65 | entity who first fixes the sounds of a performance or other sounds; 66 | and, 67 | 68 | - in the case of broadcasts, the organization that transmits the 69 | broadcast. 70 | 71 | Work is the literary and/or artistic work offered under the terms of 72 | this License including without limitation any production in the 73 | literary, scientific and artistic domain, whatever may be the mode or 74 | form of its expression including digital form, such as a book, pamphlet 75 | and other writing; a lecture, address, sermon or other work of the same 76 | nature; a dramatic or dramatico-musical work; a choreographic work or 77 | entertainment in dumb show; a musical composition with or without words; 78 | a cinematographic work to which are assimilated works expressed by a 79 | process analogous to cinematography; a work of drawing, painting, 80 | architecture, sculpture, engraving or lithography; a photographic work 81 | to which are assimilated works expressed by a process analogous to 82 | photography; a work of applied art; an illustration, map, plan, sketch 83 | or three-dimensional work relative to geography, topography, 84 | architecture or science; a performance; a broadcast; a phonogram; a 85 | compilation of data to the extent it is protected as a copyrightable 86 | work; or a work performed by a variety or circus performer to the extent 87 | it is not otherwise considered a literary or artistic work. 88 | 89 | You means an individual or entity exercising rights under this License 90 | who has not previously violated the terms of this License with respect 91 | to the Work, or who has received express permission from the Licensor to 92 | exercise rights under this License despite a previous violation. 93 | 94 | Publicly Perform means to perform public recitations of the Work and to 95 | communicate to the public those public recitations, by any means or 96 | process, including by wire or wireless means or public digital 97 | performances; to make available to the public Works in such a way that 98 | members of the public may access these Works from a place and at a place 99 | individually chosen by them; to perform the Work to the public by any 100 | means or process and the communication to the public of the performances 101 | of the Work, including by public digital performance; to broadcast and 102 | rebroadcast the Work by any means including signs, sounds or images. 103 | 104 | Reproduce is to make copies of the Work by any means including without 105 | limitation by sound or visual recordings and the right of fixation and 106 | reproducing fixations of the Work, including storage of a protected 107 | performance or phonogram in digital form or other electronic medium. 108 | 109 | Software is any digital Work which, through use of a third-party piece 110 | of Software or through the direct usage of itself on a computer system, 111 | the memory of the computer is modified dynamically or semi-dynamically. 112 | \"Software\", secondly, processes or interprets information. 113 | 114 | Source Code is Any digital Work which, through use of a third-party 115 | piece of Software or through the direct usage of itself on a computer 116 | system, the memory of the computer is modified dynamically or 117 | semi-dynamically. \"Software\", secondly, processes or interprets 118 | information. 119 | 120 | Surveilling is the use of the Work to either overtly or covertly observe 121 | and record persons and or their activities. 122 | 123 | A Network Service is the use of a piece of Software to interpret or 124 | modify information that is subsequently and directly served to users 125 | over the Internet. 126 | 127 | To Discriminate is use of a work to differentiate between humans in a 128 | such a way which prioritizes some above others on the basis of percieved 129 | membership within certain groups. 130 | 131 | Hate Speech is Communication or any form of expression which is solely 132 | for the purpose of expressing hatred for some group or advocating a form 133 | of Discrimination between humans. 134 | 135 | Coercion is leveraging of the threat of force or use of force to 136 | intimidate a person in order to gain compliance, or to offer large 137 | incentives which aim to entice a person to act against their will. 138 | 139 | # Fair Dealing Rights 140 | 141 | Nothing in this License is intended to reduce, limit, or restrict any 142 | uses free from copyright or rights arising from limitations or 143 | exceptions that are provided for in connection with the copyright 144 | protection under copyright law or other applicable laws. 145 | 146 | # License Grant 147 | 148 | Subject to the terms and conditions of this License, Licensor hereby 149 | grants You a worldwide, royalty-free, non-exclusive, perpetual (for the 150 | duration of the applicable copyright) license to exercise the rights in 151 | the Work as stated below: 152 | 153 | To Reproduce the Work, to incorporate the Work into one or more 154 | Collections, and to Reproduce the Work as incorporated in the 155 | Collections 156 | 157 | To create and Reproduce Adaptations provided that any such Adaptation, 158 | including any translation in any medium, takes reasonable steps to 159 | clearly label, demarcate or otherwise identify that changes were made to 160 | the original Work. For example, a translation could be marked \"The 161 | original work was translated from English to Spanish,\" or a 162 | modification could indicate \"The original work has been modified.\" 163 | 164 | To Distribute and Publicly Perform the Work including as incorporated in 165 | Collections. 166 | 167 | To Distribute and Publicly Perform Adaptations. The above rights may be 168 | exercised in all media and formats whether now known or hereafter 169 | devised. The above rights include the right to make such modifications 170 | as are technically necessary to exercise the rights in other media and 171 | formats. This License constitutes the entire agreement between the 172 | parties with respect to the Work licensed here. There are no 173 | understandings, agreements or representations with respect to the Work 174 | not specified here. Licensor shall not be bound by any additional 175 | provisions that may appear in any communication from You. This License 176 | may not be modified without the mutual written agreement of the Licensor 177 | and You. All rights not expressly granted by Licensor are hereby 178 | reserved, including but not limited to the rights set forth in 179 | Non-waivable Compulsory License Schemes, Waivable Compulsory License 180 | Schemes, and Voluntary License Schemes in the restrictions. 181 | 182 | # Restrictions 183 | 184 | The license granted in the license grant above is expressly made subject 185 | to and limited by the following restrictions: 186 | 187 | You may Distribute or Publicly Perform the Work only under the terms of 188 | this License. You must include a copy of, or the Uniform Resource 189 | Identifier (URI) for, this License with every copy of the Work You 190 | Distribute or Publicly Perform. You may not offer or impose any terms on 191 | the Work that restrict the terms of this License or the ability of the 192 | recipient of the Work to exercise the rights granted to that recipient 193 | under the terms of the License. You may not sublicense the Work. You 194 | must keep intact all notices that refer to this License and to the 195 | disclaimer of warranties with every copy of the Work You Distribute or 196 | Publicly Perform. When You Distribute or Publicly Perform the Work, You 197 | may not impose any effective technological measures on the Work that 198 | restrict the ability of a recipient of the Work from You to exercise the 199 | rights granted to that recipient under the terms of the License. This 200 | Section applies to the Work as incorporated in a Collection, but this 201 | does not require the Collection apart from the Work itself to be made 202 | subject to the terms of this License. If You create a Collection, upon 203 | notice from any Licensor You must, to the extent practicable, remove 204 | from the Collection any credit as requested. If You create an 205 | Adaptation, upon notice from any Licensor You must, to the extent 206 | practicable, remove from the Adaptation any credit as requested. 207 | 208 | If the Work meets the definition of Software, You may exercise the 209 | rights granted in the license grant only if You provide a copy of the 210 | corresponding Source Code from which the Work was derived in digital 211 | form, or You provide a URI for the corresponding Source Code of the 212 | Work, to any recipients upon request. 213 | 214 | If the Work is used as or for a Network Service, You may exercise the 215 | rights granted in the license grant only if You provide a copy of the 216 | corresponding Source Code from which the Work was derived in digital 217 | form, or You provide a URI for the corresponding Source Code to the 218 | Work, to any recipients of the data served or modified by the Web 219 | Service. 220 | 221 | ## 222 | 223 | You may exercise the rights granted in the license grant for any 224 | purposes only if: 225 | 226 | i. You do not use the Work for the purpose of inflicting Bodily Harm on 227 | human beings (subject to criminal prosecution or otherwise) outside 228 | of providing medical aid or undergoing a voluntary procedure under 229 | no form of Coercion. 230 | 231 | ii. You do not use the Work for the purpose of Surveilling or tracking 232 | individuals for financial gain. 233 | 234 | iii. You do not use the Work in an Act of War. 235 | 236 | iv. You do not use the Work for the purpose of supporting or profiting 237 | from an Act of War. 238 | 239 | v. You do not use the Work for the purpose of Incarceration. 240 | 241 | vi. You do not use the Work for the purpose of extracting, processing, 242 | or refining, oil, gas, or coal. Or to in any other way to 243 | deliberately pollute the environment as a byproduct of manufacturing 244 | or irresponsible disposal of hazardous materials. 245 | 246 | vii. You do not use the Work for the purpose of expediting, 247 | coordinating, or facilitating paid work undertaken by individuals 248 | under the age of 12 years. 249 | 250 | viii. You do not use the Work to either Discriminate or spread Hate 251 | Speech on the basis of sex, sexual orientation, gender identity, 252 | race, age, disability, color, national origin, religion, caste, or 253 | lower economic status. 254 | 255 | ## 256 | 257 | If You Distribute, or Publicly Perform the Work or any Adaptations or 258 | Collections, You must, unless a request has been made by any Licensor to 259 | remove credit from a Collection or Adaptation, keep intact all copyright 260 | notices for the Work and provide, reasonable to the medium or means You 261 | are utilizing: 262 | 263 | i. the name of the Original Author (or pseudonym, if applicable) if 264 | supplied, and/or if the Original Author and/or Licensor designate 265 | another party or parties (e.g., a sponsor institute, publishing 266 | entity, journal) for attribution (\"Attribution Parties\") in 267 | Licensor\'s copyright notice, terms of service or by other 268 | reasonable means, the name of such party or parties; 269 | 270 | ii. the title of the Work if supplied; 271 | 272 | iii. to the extent reasonably practicable, the URI, if any, that 273 | Licensor to be associated with the Work, unless such URI does not 274 | refer to the copyright notice or licensing information for the 275 | Work; and, 276 | 277 | iv. in the case of an Adaptation, a credit identifying the use of the 278 | Work in the Adaptation (e.g., \"French translation of the Work by 279 | Original Author,\" or \"Screenplay based on original Work by 280 | Original Author\"). 281 | 282 | If any Licensor has sent notice to request removing credit, You must, to 283 | the extent practicable, remove any credit as requested. The credit 284 | required by this Section may be implemented in any reasonable manner; 285 | provided, however, that in the case of an Adaptation or Collection, at a 286 | minimum such credit will appear, if a credit for all contributing 287 | authors of the Adaptation or Collection appears, then as part of these 288 | credits and in a manner at least as prominent as the credits for the 289 | other contributing authors. For the avoidance of doubt, You may only use 290 | the credit required by this Section for the purpose of attribution in 291 | the manner set out above and, by exercising Your rights under this 292 | License, You may not implicitly or explicitly assert or imply any 293 | connection with, sponsorship or endorsement by the Original Author, 294 | Licensor and/or Attribution Parties, as appropriate, of You or Your use 295 | of the Work, without the separate, express prior written permission of 296 | the Original Author, Licensor and/or Attribution Parties. 297 | 298 | Except as otherwise agreed in writing by the Licensor or as may be 299 | otherwise permitted by applicable law, if You Reproduce, Distribute or 300 | Publicly Perform the Work either by itself or as part of any Adaptations 301 | or Collections, You must not distort, mutilate, modify or take other 302 | derogatory action in relation to the Work which would be prejudicial to 303 | the Original Author\'s honor or reputation. Licensor agrees that in 304 | those jurisdictions (e.g. Japan), in which any exercise of the right 305 | granted in the license grant of this License (the right to make 306 | Adaptations) would be deemed to be a distortion, mutilation, 307 | modification or other derogatory action prejudicial to the Original 308 | Author\'s honor and reputation, the Licensor will waive or not assert, 309 | as appropriate, this Section, to the fullest extent permitted by the 310 | applicable national law, to enable You to reasonably exercise Your right 311 | under the license grant of this License (right to make Adaptations) but 312 | not otherwise. 313 | 314 | Do not make any legal claim against anyone accusing the Work, with or 315 | without changes, alone or with other works, of infringing any patent 316 | claim. 317 | 318 | # Representations Warranties and Disclaimer 319 | 320 | UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR 321 | OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY 322 | KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, 323 | INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, 324 | FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF 325 | LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, 326 | WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE 327 | EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 328 | 329 | # Limitation on Liability 330 | 331 | EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL 332 | LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, 333 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF 334 | THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED 335 | OF THE POSSIBILITY OF SUCH DAMAGES. 336 | 337 | # Termination 338 | 339 | This License and the rights granted hereunder will terminate 340 | automatically upon any breach by You of the terms of this License. 341 | Individuals or entities who have received Adaptations or Collections 342 | from You under this License, however, will not have their licenses 343 | terminated provided such individuals or entities remain in full 344 | compliance with those licenses. The Sections on definitions, fair 345 | dealing rights, representations, warranties, and disclaimer, limitation 346 | on liability, termination, and revised license versions will survive any 347 | termination of this License. 348 | 349 | Subject to the above terms and conditions, the license granted here is 350 | perpetual (for the duration of the applicable copyright in the Work). 351 | Notwithstanding the above, Licensor reserves the right to release the 352 | Work under different license terms or to stop distributing the Work at 353 | any time; provided, however that any such election will not serve to 354 | withdraw this License (or any other license that has been, or is 355 | required to be, granted under the terms of this License), and this 356 | License will continue in full force and effect unless terminated as 357 | stated above. 358 | 359 | # Revised License Versions 360 | 361 | This License may receive future revisions in the original spirit of the 362 | license intended to strengthen This License. Each version of This 363 | License has an incrementing version number. 364 | 365 | Unless otherwise specified like in the below subsection The Licensor has 366 | only granted this current version of This License for The Work. In this 367 | case future revisions do not apply. 368 | 369 | The Licensor may specify that the latest available revision of This 370 | License be used for The Work by either explicitly writing so or by 371 | suffixing the License URI with a \"+\" symbol. 372 | 373 | The Licensor may specify that The Work is also available under the terms 374 | of This License\'s current revision as well as specific future 375 | revisions. The Licensor may do this by writing it explicitly or 376 | suffixing the License URI with any additional version numbers each 377 | separated by a comma. 378 | 379 | # Miscellaneous 380 | 381 | Each time You Distribute or Publicly Perform the Work or a Collection, 382 | the Licensor offers to the recipient a license to the Work on the same 383 | terms and conditions as the license granted to You under this License. 384 | 385 | Each time You Distribute or Publicly Perform an Adaptation, Licensor 386 | offers to the recipient a license to the original Work on the same terms 387 | and conditions as the license granted to You under this License. 388 | 389 | If the Work is classified as Software, each time You Distribute or 390 | Publicly Perform an Adaptation, Licensor offers to the recipient a copy 391 | and/or URI of the corresponding Source Code on the same terms and 392 | conditions as the license granted to You under this License. 393 | 394 | If the Work is used as a Network Service, each time You Distribute or 395 | Publicly Perform an Adaptation, or serve data derived from the Software, 396 | the Licensor offers to any recipients of the data a copy and/or URI of 397 | the corresponding Source Code on the same terms and conditions as the 398 | license granted to You under this License. 399 | 400 | If any provision of this License is invalid or unenforceable under 401 | applicable law, it shall not affect the validity or enforceability of 402 | the remainder of the terms of this License, and without further action 403 | by the parties to this agreement, such provision shall be reformed to 404 | the minimum extent necessary to make such provision valid and 405 | enforceable. 406 | 407 | No term or provision of this License shall be deemed waived and no 408 | breach consented to unless such waiver or consent shall be in writing 409 | and signed by the party to be charged with such waiver or consent. 410 | 411 | This License constitutes the entire agreement between the parties with 412 | respect to the Work licensed here. There are no understandings, 413 | agreements or representations with respect to the Work not specified 414 | here. Licensor shall not be bound by any additional provisions that may 415 | appear in any communication from You. This License may not be modified 416 | without the mutual written agreement of the Licensor and You. 417 | 418 | The rights granted under, and the subject matter referenced, in this 419 | License were drafted utilizing the terminology of the Berne Convention 420 | for the Protection of Literary and Artistic Works (as amended on 421 | September 28, 1979), the Rome Convention of 1961, the WIPO Copyright 422 | Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and 423 | the Universal Copyright Convention (as revised on July 24, 1971). These 424 | rights and subject matter take effect in the relevant jurisdiction in 425 | which the License terms are sought to be enforced according to the 426 | corresponding provisions of the implementation of those treaty 427 | provisions in the applicable national law. If the standard suite of 428 | rights granted under applicable copyright law includes additional rights 429 | not granted under this License, such additional rights are deemed to be 430 | included in the License; this License is not intended to restrict the 431 | license of any rights under applicable law. 432 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # URL Eater 2 | Clean unnecessary parameters from URLs copied to clipboard 3 | 4 | ## Usage 5 | Run with a filter file that specifies which parameters should be removed: 6 | ``` 7 | url-eater denylist.kdl 8 | ``` 9 | An example filter file: 10 | ```d 11 | category "Spotify" { 12 | params "context@open.spotify.com" "si@open.spotify.com" 13 | } 14 | category "Campaign tracking (itm)" { 15 | params "itm_*" 16 | } 17 | category "Campaign tracking (stm)" disabled=true { 18 | params "stm_*" 19 | } 20 | ``` 21 | Categories are used to structure filter lists and allow disabling/enabling filters in groups. 22 | Each parameter applies to all URLs, unless a domain like `@example.com` is specified at the end. 23 | Both the parameter and the domain parts can contain wildcards. Use `*` to match 0 or more characters, and `?` to match exactly one character. 24 | The structure is based on [NeatURL's format](https://github.com/Smile4ever/Neat-URL/#default-blocked-parameters), with a few differences (aside from a different file format): 25 | - Single character matching (`?`) is supported. 26 | - `$` and `!` rules are currently unsupported. 27 | 28 | The intended use case is running the program as a background service. 29 | 30 | ## Example 31 | Before: 32 | ``` 33 | https://open.spotify.com/track/0ibuggkWTSDXHo25S0Qqvj?si=e4c675cbaee94c3a 34 | ``` 35 | After: 36 | ``` 37 | https://open.spotify.com/track/0ibuggkWTSDXHo25S0Qqvj 38 | ``` 39 | 40 | ## Usage example 41 | This repository also contains a Nix flake. It can be used in a NixOS configuration like this: 42 | 1. Add flake to inputs: 43 | ```nix 44 | url-eater.url = "github:AgathaSorceress/url-eater"; 45 | url-eater.inputs.nixpkgs.follows = "nixpkgs"; # optional 46 | ``` 47 | 2. Adding output: 48 | ```nix 49 | outputs = inputs@{ self, nixpkgs, url-eater, ... }: 50 | ``` 51 | 3. Import NixOS module 52 | ```nix 53 | imports = [ url-eater.nixosModules.default ]; 54 | ``` 55 | 4. Configure the module: 56 | ```nix 57 | { ... }: { 58 | services.url-eater = { 59 | enable = true; 60 | filters = '' 61 | category "Spotify" { 62 | params "context@open.spotify.com" "si@open.spotify.com" 63 | } 64 | category "Twitter" { 65 | params "cxt@*.twitter.com" "ref_*@*.twitter.com" "s@*.twitter.com" "t@*.twitter.com" "twclid" 66 | } 67 | ''; 68 | }; 69 | } 70 | ``` 71 | 72 | ## Building from source 73 | Clone this repository, then run: 74 | ```sh 75 | cargo build --release 76 | ``` 77 | The output binary will be in `target/release/url-eater` 78 | 79 | Alternatively, 80 | ```sh 81 | nix build github:AgathaSorceress/url-eater 82 | ``` 83 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | (import ( 2 | fetchTarball { 3 | url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; 4 | sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; } 5 | ) { 6 | src = ./.; 7 | }).defaultNix 8 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "naersk": { 4 | "inputs": { 5 | "nixpkgs": [ 6 | "nixpkgs" 7 | ] 8 | }, 9 | "locked": { 10 | "lastModified": 1721727458, 11 | "narHash": "sha256-r/xppY958gmZ4oTfLiHN0ZGuQ+RSTijDblVgVLFi1mw=", 12 | "owner": "nix-community", 13 | "repo": "naersk", 14 | "rev": "3fb418eaf352498f6b6c30592e3beb63df42ef11", 15 | "type": "github" 16 | }, 17 | "original": { 18 | "owner": "nix-community", 19 | "ref": "master", 20 | "repo": "naersk", 21 | "type": "github" 22 | } 23 | }, 24 | "nixpkgs": { 25 | "locked": { 26 | "lastModified": 1733097829, 27 | "narHash": "sha256-9hbb1rqGelllb4kVUCZ307G2k3/UhmA8PPGBoyuWaSw=", 28 | "owner": "NixOS", 29 | "repo": "nixpkgs", 30 | "rev": "2c15aa59df0017ca140d9ba302412298ab4bf22a", 31 | "type": "github" 32 | }, 33 | "original": { 34 | "owner": "NixOS", 35 | "ref": "nixpkgs-unstable", 36 | "repo": "nixpkgs", 37 | "type": "github" 38 | } 39 | }, 40 | "root": { 41 | "inputs": { 42 | "naersk": "naersk", 43 | "nixpkgs": "nixpkgs", 44 | "utils": "utils" 45 | } 46 | }, 47 | "systems": { 48 | "locked": { 49 | "lastModified": 1681028828, 50 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 51 | "owner": "nix-systems", 52 | "repo": "default", 53 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 54 | "type": "github" 55 | }, 56 | "original": { 57 | "owner": "nix-systems", 58 | "repo": "default", 59 | "type": "github" 60 | } 61 | }, 62 | "utils": { 63 | "inputs": { 64 | "systems": "systems" 65 | }, 66 | "locked": { 67 | "lastModified": 1731533236, 68 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 69 | "owner": "numtide", 70 | "repo": "flake-utils", 71 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 72 | "type": "github" 73 | }, 74 | "original": { 75 | "owner": "numtide", 76 | "repo": "flake-utils", 77 | "type": "github" 78 | } 79 | } 80 | }, 81 | "root": "root", 82 | "version": 7 83 | } 84 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | naersk.url = "github:nix-community/naersk/master"; 4 | naersk.inputs.nixpkgs.follows = "nixpkgs"; 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 6 | utils.url = "github:numtide/flake-utils"; 7 | }; 8 | 9 | outputs = 10 | { 11 | self, 12 | nixpkgs, 13 | utils, 14 | naersk, 15 | }: 16 | utils.lib.eachDefaultSystem ( 17 | system: 18 | let 19 | pkgs = import nixpkgs { inherit system; }; 20 | naersk-lib = pkgs.callPackage naersk { }; 21 | in 22 | { 23 | packages.default = naersk-lib.buildPackage { 24 | src = ./.; 25 | buildInputs = with pkgs; lib.optionals stdenv.isDarwin [ darwin.apple_sdk.frameworks.AppKit ]; 26 | }; 27 | devShells.default = 28 | with pkgs; 29 | mkShell { 30 | buildInputs = [ 31 | cargo 32 | rustc 33 | rustfmt 34 | pre-commit 35 | rustPackages.clippy 36 | rust-analyzer 37 | ]; 38 | RUST_SRC_PATH = rustPlatform.rustLibSrc; 39 | }; 40 | } 41 | ) 42 | // { 43 | nixosModules.default = 44 | { 45 | config, 46 | lib, 47 | pkgs, 48 | ... 49 | }: 50 | with lib; 51 | let 52 | cfg = config.services.url-eater; 53 | in 54 | { 55 | options.services.url-eater = { 56 | enable = mkEnableOption "Enables the URL Eater service"; 57 | filters = mkOption { 58 | type = types.str; 59 | example = '' 60 | category "Spotify" { 61 | params "context@open.spotify.com" "si@open.spotify.com" 62 | } 63 | category "Twitter" { 64 | params "cxt@*.twitter.com" "ref_*@*.twitter.com" "s@*.twitter.com" "t@*.twitter.com" "twclid" 65 | } 66 | ''; 67 | description = '' 68 | A list of filters to use, in the KDL file format. 69 | ''; 70 | }; 71 | }; 72 | 73 | config = mkIf cfg.enable { 74 | systemd.user.services."url-eater" = 75 | let 76 | filters = pkgs.writeText "filters.kdl" cfg.filters; 77 | pkg = self.packages.${pkgs.system}.default; 78 | in 79 | { 80 | description = "Clipboard URL cleanup service"; 81 | 82 | after = [ "graphical-session-pre.target" ]; 83 | wantedBy = [ "graphical-session.target" ]; 84 | 85 | script = '' 86 | exec ${pkg}/bin/url-eater ${filters} 87 | ''; 88 | }; 89 | }; 90 | }; 91 | }; 92 | } 93 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use miette::{IntoDiagnostic, Result}; 2 | use std::{fs, ops::Deref}; 3 | 4 | #[derive(knuffel::Decode, Debug)] 5 | pub(crate) struct Category { 6 | #[knuffel(argument)] 7 | pub name: String, 8 | #[knuffel(property, default)] 9 | disabled: bool, 10 | #[knuffel(child, unwrap(arguments))] 11 | pub params: Vec, 12 | } 13 | 14 | pub(crate) struct Config(Vec); 15 | 16 | impl Config { 17 | /// Read filter file 18 | pub fn from_file(path: &str) -> Result { 19 | let filters = fs::read_to_string(path) 20 | .into_diagnostic() 21 | .map_err(|err| err.context(format!("Could not read file `{path}`")))?; 22 | 23 | let filters = knuffel::parse::>("config.kdl", &filters)? 24 | .into_iter() 25 | .filter(|v| !v.disabled) 26 | .collect::>(); 27 | 28 | Ok(Config(filters)) 29 | } 30 | 31 | pub fn flat(&self) -> Vec { 32 | self.iter().flat_map(|v| v.params.clone()).collect() 33 | } 34 | } 35 | 36 | impl Deref for Config { 37 | type Target = Vec; 38 | 39 | fn deref(&self) -> &Self::Target { 40 | &self.0 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use arboard::Clipboard; 2 | use memoize::memoize; 3 | use miette::{miette, Result}; 4 | use std::{borrow::Cow, env, time::Duration}; 5 | use url::Url; 6 | use wildmatch::WildMatch; 7 | 8 | mod config; 9 | use config::Config; 10 | 11 | #[cfg(test)] 12 | mod tests; 13 | 14 | /// How often should clipboard be checked for changes (0 will result in high CPU usage) 15 | const ITERATION_DELAY: Duration = Duration::from_millis(250); 16 | 17 | fn main() -> Result<()> { 18 | // Get filter file path 19 | let path = env::args() 20 | .nth(1) 21 | .ok_or_else(|| miette!("Please provide a path to a KDL file with parameter filters"))?; 22 | 23 | let filters = Config::from_file(&path)?; 24 | 25 | println!("Loaded with categories:"); 26 | for filter in &*filters { 27 | println!("\t• {}", filter.name); 28 | } 29 | 30 | // Initialize clipboard context 31 | let mut clipboard = Clipboard::new() 32 | .map_err(|e| miette!(format!("Could not initialize clipboard context: {e}")))?; 33 | let mut last_contents = clipboard.get_text().unwrap_or_else(|_| String::new()); 34 | loop { 35 | std::thread::sleep(ITERATION_DELAY); 36 | if let Ok(contents) = clipboard.get_text() { 37 | // Empty clipboard (Linux) 38 | if contents.is_empty() { 39 | continue; 40 | }; 41 | 42 | // Clipboard changed 43 | if contents != last_contents { 44 | last_contents = contents.clone(); 45 | if let Ok(url) = clean_url(contents, filters.flat()) { 46 | // Update clipboard 47 | clipboard 48 | .set_text(url.clone()) 49 | .map_err(|e| miette!(format!("Couldn't set clipboard contents: {e}")))?; 50 | last_contents = url; 51 | }; 52 | }; 53 | } 54 | } 55 | } 56 | 57 | #[memoize(Capacity: 1024)] 58 | fn clean_url(text: String, patterns: Vec) -> Result { 59 | let mut url = Url::parse(&text).map_err(|e| format!("Contents are not a valid URL: {e}"))?; 60 | let url_inner = url.clone(); 61 | 62 | // Skip URLs without a host 63 | let Some(host) = url_inner.host_str() else { 64 | return Err(format!("URL {url_inner} does not have a host")); 65 | }; 66 | 67 | for pattern in &patterns { 68 | let url_inner = url.clone(); 69 | if let Some((param, domain)) = pattern.split_once('@') { 70 | if WildMatch::new(domain).matches(host) { 71 | // Filter parameters to exclude blocked entries 72 | let query = url_inner 73 | .query_pairs() 74 | .filter(|x| !WildMatch::new(param).matches(&x.0)); 75 | // Replace parameters in URL 76 | replace_query(&mut url, query); 77 | } 78 | } else { 79 | // Filter parameters to exclude blocked entries 80 | let query = url_inner 81 | .query_pairs() 82 | .filter(|x| !WildMatch::new(pattern).matches(&x.0)); 83 | // Replace parameters in URL 84 | replace_query(&mut url, query); 85 | } 86 | } 87 | 88 | Ok(url.to_string()) 89 | } 90 | 91 | fn replace_query<'a>( 92 | url: &mut Url, 93 | query_pairs: impl IntoIterator, Cow<'a, str>)>, 94 | ) { 95 | url.set_query(None); 96 | for (k, v) in query_pairs { 97 | if v.is_empty() { 98 | url.query_pairs_mut().append_key_only(&k); 99 | } else { 100 | url.query_pairs_mut().append_pair(&k, &v); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | #[cfg(test)] 4 | use pretty_assertions::assert_eq; 5 | 6 | const PATTERNS: [&str; 2] = ["delete_me", "test@example.com"]; 7 | 8 | #[test] 9 | fn query_parameters() -> Result<(), String> { 10 | for (url, expected) in [ 11 | ("http://test.org/meow", "http://test.org/meow"), 12 | ("http://test.org/page?delete_me", "http://test.org/page"), 13 | ( 14 | "http://test.org/page?delete_me&keep_me", 15 | "http://test.org/page?keep_me", 16 | ), 17 | ] { 18 | assert_eq!( 19 | clean_url( 20 | url.to_owned(), 21 | PATTERNS.into_iter().map(|v| v.into()).collect() 22 | )?, 23 | expected.to_owned() 24 | ); 25 | } 26 | 27 | Ok(()) 28 | } 29 | 30 | #[test] 31 | fn url_fragments() -> Result<(), String> { 32 | for (url, expected) in [ 33 | ( 34 | "http://test.org/page?delete_me#fragment", 35 | "http://test.org/page#fragment", 36 | ), 37 | ( 38 | "http://test.org/page#fragment", 39 | "http://test.org/page#fragment", 40 | ), 41 | ] { 42 | assert_eq!( 43 | clean_url( 44 | url.to_owned(), 45 | PATTERNS.into_iter().map(|v| v.into()).collect() 46 | )?, 47 | expected.to_owned() 48 | ); 49 | } 50 | 51 | Ok(()) 52 | } 53 | --------------------------------------------------------------------------------