├── .gitignore ├── .rustfmt.toml ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── bindings └── bemenu.h ├── build.rs ├── install.sh ├── resources ├── config.toml └── wayclip.service ├── rust-toolchain.toml └── src ├── clipboard └── mod.rs ├── communication └── mod.rs ├── config ├── cli.rs ├── consts.rs ├── data.rs ├── error.rs ├── file.rs ├── install.rs ├── mod.rs └── resources.rs ├── input └── mod.rs ├── main.rs ├── menu ├── bemenu.rs └── mod.rs └── wayland └── mod.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width=120 2 | tab_spaces=2 -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [0.4.1] - 2023-11-19 6 | 7 | Fixing a double free in the drop for BeMenu and minorly reworking logging. 8 | 9 | ## [0.4.0] - 2023-11-3 10 | 11 | This release merges PR #2 from @Vilhelm-Ian, which adds the ability to clear the clipboard. 12 | 13 | ## [0.3.0] - 2023-10-2 14 | 15 | This release fixes a memory leak. There is still another memory leak around bemenu's use of cairo but still working on figuring it out. 16 | 17 | ## [0.2.1] - 2023-06-4 18 | 19 | This release fixes a bug where wayclip would rearrange the clipboard after paste from the wrong side of the vector. It also forces paste mimetype to what is set in config.toml. This should fix intermittent pasting bugs. Also bumps rust nightly to 1.72. Run `cargo clean` if you are getting compilation errors, as sparse-by-default may break `cargo check` and rust-analyzer. 20 | 21 | ## [0.2.0] - 2023-05-14 22 | 23 | This release adds dedupe support, disables image copying by default (since it 24 | makes the file large and really should be stored separately), and improves error messages. 25 | 26 | - Added: Dedupe support 27 | - Added: config file entry to disable image copying 28 | - Added: Better error messages 29 | - Fixed: logging verbosity 30 | 31 | ## [0.1.0] - 2023-05-13 32 | 33 | First release! See README for features. 34 | -------------------------------------------------------------------------------- /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 = "adler32" 7 | version = "1.2.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" 10 | 11 | [[package]] 12 | name = "aead" 13 | version = "0.5.2" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" 16 | dependencies = [ 17 | "crypto-common", 18 | "generic-array", 19 | ] 20 | 21 | [[package]] 22 | name = "aes" 23 | version = "0.8.4" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" 26 | dependencies = [ 27 | "cfg-if", 28 | "cipher", 29 | "cpufeatures", 30 | ] 31 | 32 | [[package]] 33 | name = "aes-gcm" 34 | version = "0.10.3" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" 37 | dependencies = [ 38 | "aead", 39 | "aes", 40 | "cipher", 41 | "ctr", 42 | "ghash", 43 | "subtle", 44 | ] 45 | 46 | [[package]] 47 | name = "aho-corasick" 48 | version = "1.1.3" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 51 | dependencies = [ 52 | "memchr", 53 | ] 54 | 55 | [[package]] 56 | name = "anstream" 57 | version = "0.6.14" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" 60 | dependencies = [ 61 | "anstyle", 62 | "anstyle-parse", 63 | "anstyle-query", 64 | "anstyle-wincon", 65 | "colorchoice", 66 | "is_terminal_polyfill", 67 | "utf8parse", 68 | ] 69 | 70 | [[package]] 71 | name = "anstyle" 72 | version = "1.0.7" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" 75 | 76 | [[package]] 77 | name = "anstyle-parse" 78 | version = "0.2.4" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" 81 | dependencies = [ 82 | "utf8parse", 83 | ] 84 | 85 | [[package]] 86 | name = "anstyle-query" 87 | version = "1.1.0" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" 90 | dependencies = [ 91 | "windows-sys 0.52.0", 92 | ] 93 | 94 | [[package]] 95 | name = "anstyle-wincon" 96 | version = "3.0.3" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" 99 | dependencies = [ 100 | "anstyle", 101 | "windows-sys 0.52.0", 102 | ] 103 | 104 | [[package]] 105 | name = "async-channel" 106 | version = "2.3.1" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" 109 | dependencies = [ 110 | "concurrent-queue", 111 | "event-listener-strategy", 112 | "futures-core", 113 | "pin-project-lite", 114 | ] 115 | 116 | [[package]] 117 | name = "async-task" 118 | version = "4.7.1" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" 121 | 122 | [[package]] 123 | name = "atomic" 124 | version = "0.6.0" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" 127 | dependencies = [ 128 | "bytemuck", 129 | ] 130 | 131 | [[package]] 132 | name = "atomic-waker" 133 | version = "1.1.2" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 136 | 137 | [[package]] 138 | name = "autocfg" 139 | version = "1.3.0" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 142 | 143 | [[package]] 144 | name = "bincode" 145 | version = "1.3.3" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 148 | dependencies = [ 149 | "serde", 150 | ] 151 | 152 | [[package]] 153 | name = "bindgen" 154 | version = "0.66.1" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" 157 | dependencies = [ 158 | "bitflags 2.5.0", 159 | "cexpr", 160 | "clang-sys", 161 | "lazy_static", 162 | "lazycell", 163 | "log", 164 | "peeking_take_while", 165 | "prettyplease", 166 | "proc-macro2", 167 | "quote", 168 | "regex", 169 | "rustc-hash", 170 | "shlex", 171 | "syn 2.0.66", 172 | "which", 173 | ] 174 | 175 | [[package]] 176 | name = "bindgen" 177 | version = "0.68.1" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" 180 | dependencies = [ 181 | "bitflags 2.5.0", 182 | "cexpr", 183 | "clang-sys", 184 | "lazy_static", 185 | "lazycell", 186 | "log", 187 | "peeking_take_while", 188 | "prettyplease", 189 | "proc-macro2", 190 | "quote", 191 | "regex", 192 | "rustc-hash", 193 | "shlex", 194 | "syn 2.0.66", 195 | "which", 196 | ] 197 | 198 | [[package]] 199 | name = "bitflags" 200 | version = "1.3.2" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 203 | 204 | [[package]] 205 | name = "bitflags" 206 | version = "2.5.0" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 209 | 210 | [[package]] 211 | name = "bitvec" 212 | version = "1.0.1" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 215 | dependencies = [ 216 | "funty", 217 | "radium", 218 | "tap", 219 | "wyz", 220 | ] 221 | 222 | [[package]] 223 | name = "block-buffer" 224 | version = "0.9.0" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 227 | dependencies = [ 228 | "generic-array", 229 | ] 230 | 231 | [[package]] 232 | name = "block-buffer" 233 | version = "0.10.4" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 236 | dependencies = [ 237 | "generic-array", 238 | ] 239 | 240 | [[package]] 241 | name = "blocking" 242 | version = "1.6.1" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" 245 | dependencies = [ 246 | "async-channel", 247 | "async-task", 248 | "futures-io", 249 | "futures-lite", 250 | "piper", 251 | ] 252 | 253 | [[package]] 254 | name = "bytemuck" 255 | version = "1.16.0" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" 258 | 259 | [[package]] 260 | name = "byteorder" 261 | version = "1.5.0" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 264 | 265 | [[package]] 266 | name = "cc" 267 | version = "1.0.99" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" 270 | 271 | [[package]] 272 | name = "cexpr" 273 | version = "0.6.0" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 276 | dependencies = [ 277 | "nom", 278 | ] 279 | 280 | [[package]] 281 | name = "cfb" 282 | version = "0.7.3" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" 285 | dependencies = [ 286 | "byteorder", 287 | "fnv", 288 | "uuid", 289 | ] 290 | 291 | [[package]] 292 | name = "cfg-if" 293 | version = "1.0.0" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 296 | 297 | [[package]] 298 | name = "chacha20" 299 | version = "0.9.1" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" 302 | dependencies = [ 303 | "cfg-if", 304 | "cipher", 305 | "cpufeatures", 306 | ] 307 | 308 | [[package]] 309 | name = "chacha20poly1305" 310 | version = "0.10.1" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" 313 | dependencies = [ 314 | "aead", 315 | "chacha20", 316 | "cipher", 317 | "poly1305", 318 | "zeroize", 319 | ] 320 | 321 | [[package]] 322 | name = "cipher" 323 | version = "0.4.4" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" 326 | dependencies = [ 327 | "crypto-common", 328 | "inout", 329 | "zeroize", 330 | ] 331 | 332 | [[package]] 333 | name = "clang-sys" 334 | version = "1.8.1" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" 337 | dependencies = [ 338 | "glob", 339 | "libc", 340 | "libloading", 341 | ] 342 | 343 | [[package]] 344 | name = "clap" 345 | version = "4.5.7" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" 348 | dependencies = [ 349 | "clap_builder", 350 | "clap_derive", 351 | ] 352 | 353 | [[package]] 354 | name = "clap_builder" 355 | version = "4.5.7" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" 358 | dependencies = [ 359 | "anstream", 360 | "anstyle", 361 | "clap_lex", 362 | "strsim", 363 | ] 364 | 365 | [[package]] 366 | name = "clap_derive" 367 | version = "4.5.5" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" 370 | dependencies = [ 371 | "heck", 372 | "proc-macro2", 373 | "quote", 374 | "syn 2.0.66", 375 | ] 376 | 377 | [[package]] 378 | name = "clap_lex" 379 | version = "0.7.1" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" 382 | 383 | [[package]] 384 | name = "cocoon" 385 | version = "0.3.3" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "f3da52429f9a6d0652b469b35f877e4d92e7f12238d4870d13622c87ab2a2ea9" 388 | dependencies = [ 389 | "aes-gcm", 390 | "chacha20poly1305", 391 | "hmac", 392 | "pbkdf2", 393 | "rand", 394 | "sha2 0.9.9", 395 | "zeroize", 396 | ] 397 | 398 | [[package]] 399 | name = "colorchoice" 400 | version = "1.0.1" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" 403 | 404 | [[package]] 405 | name = "concurrent-queue" 406 | version = "2.5.0" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 409 | dependencies = [ 410 | "crossbeam-utils", 411 | ] 412 | 413 | [[package]] 414 | name = "cpufeatures" 415 | version = "0.2.12" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 418 | dependencies = [ 419 | "libc", 420 | ] 421 | 422 | [[package]] 423 | name = "crc32fast" 424 | version = "1.4.2" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 427 | dependencies = [ 428 | "cfg-if", 429 | ] 430 | 431 | [[package]] 432 | name = "crossbeam-channel" 433 | version = "0.5.13" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" 436 | dependencies = [ 437 | "crossbeam-utils", 438 | ] 439 | 440 | [[package]] 441 | name = "crossbeam-utils" 442 | version = "0.8.20" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 445 | 446 | [[package]] 447 | name = "crypto-common" 448 | version = "0.1.6" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 451 | dependencies = [ 452 | "generic-array", 453 | "typenum", 454 | ] 455 | 456 | [[package]] 457 | name = "crypto-mac" 458 | version = "0.11.1" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" 461 | dependencies = [ 462 | "generic-array", 463 | "subtle", 464 | ] 465 | 466 | [[package]] 467 | name = "ctr" 468 | version = "0.9.2" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" 471 | dependencies = [ 472 | "cipher", 473 | ] 474 | 475 | [[package]] 476 | name = "deranged" 477 | version = "0.3.11" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 480 | dependencies = [ 481 | "powerfmt", 482 | ] 483 | 484 | [[package]] 485 | name = "derive-new" 486 | version = "0.5.9" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" 489 | dependencies = [ 490 | "proc-macro2", 491 | "quote", 492 | "syn 1.0.109", 493 | ] 494 | 495 | [[package]] 496 | name = "digest" 497 | version = "0.9.0" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 500 | dependencies = [ 501 | "generic-array", 502 | ] 503 | 504 | [[package]] 505 | name = "digest" 506 | version = "0.10.7" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 509 | dependencies = [ 510 | "block-buffer 0.10.4", 511 | "crypto-common", 512 | ] 513 | 514 | [[package]] 515 | name = "dirs" 516 | version = "5.0.1" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" 519 | dependencies = [ 520 | "dirs-sys", 521 | ] 522 | 523 | [[package]] 524 | name = "dirs-sys" 525 | version = "0.4.1" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" 528 | dependencies = [ 529 | "libc", 530 | "option-ext", 531 | "redox_users", 532 | "windows-sys 0.48.0", 533 | ] 534 | 535 | [[package]] 536 | name = "dlib" 537 | version = "0.5.2" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" 540 | dependencies = [ 541 | "libloading", 542 | ] 543 | 544 | [[package]] 545 | name = "downcast-rs" 546 | version = "1.2.1" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" 549 | 550 | [[package]] 551 | name = "either" 552 | version = "1.12.0" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" 555 | 556 | [[package]] 557 | name = "equivalent" 558 | version = "1.0.1" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 561 | 562 | [[package]] 563 | name = "errno" 564 | version = "0.3.9" 565 | source = "registry+https://github.com/rust-lang/crates.io-index" 566 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 567 | dependencies = [ 568 | "libc", 569 | "windows-sys 0.52.0", 570 | ] 571 | 572 | [[package]] 573 | name = "evdev" 574 | version = "0.12.2" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "ab6055a93a963297befb0f4f6e18f314aec9767a4bbe88b151126df2433610a7" 577 | dependencies = [ 578 | "bitvec", 579 | "cfg-if", 580 | "libc", 581 | "nix 0.23.2", 582 | "paste", 583 | "thiserror", 584 | ] 585 | 586 | [[package]] 587 | name = "event-listener" 588 | version = "5.3.1" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" 591 | dependencies = [ 592 | "concurrent-queue", 593 | "parking", 594 | "pin-project-lite", 595 | ] 596 | 597 | [[package]] 598 | name = "event-listener-strategy" 599 | version = "0.5.2" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" 602 | dependencies = [ 603 | "event-listener", 604 | "pin-project-lite", 605 | ] 606 | 607 | [[package]] 608 | name = "fastrand" 609 | version = "2.1.0" 610 | source = "registry+https://github.com/rust-lang/crates.io-index" 611 | checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" 612 | 613 | [[package]] 614 | name = "figment" 615 | version = "0.10.19" 616 | source = "registry+https://github.com/rust-lang/crates.io-index" 617 | checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" 618 | dependencies = [ 619 | "atomic", 620 | "serde", 621 | "toml", 622 | "uncased", 623 | "version_check", 624 | ] 625 | 626 | [[package]] 627 | name = "fixedbitset" 628 | version = "0.4.2" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" 631 | 632 | [[package]] 633 | name = "fnv" 634 | version = "1.0.7" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 637 | 638 | [[package]] 639 | name = "funty" 640 | version = "2.0.0" 641 | source = "registry+https://github.com/rust-lang/crates.io-index" 642 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 643 | 644 | [[package]] 645 | name = "futures-core" 646 | version = "0.3.30" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 649 | 650 | [[package]] 651 | name = "futures-io" 652 | version = "0.3.30" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 655 | 656 | [[package]] 657 | name = "futures-lite" 658 | version = "2.3.0" 659 | source = "registry+https://github.com/rust-lang/crates.io-index" 660 | checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" 661 | dependencies = [ 662 | "futures-core", 663 | "pin-project-lite", 664 | ] 665 | 666 | [[package]] 667 | name = "generic-array" 668 | version = "0.14.7" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 671 | dependencies = [ 672 | "typenum", 673 | "version_check", 674 | ] 675 | 676 | [[package]] 677 | name = "getrandom" 678 | version = "0.2.15" 679 | source = "registry+https://github.com/rust-lang/crates.io-index" 680 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 681 | dependencies = [ 682 | "cfg-if", 683 | "libc", 684 | "wasi", 685 | ] 686 | 687 | [[package]] 688 | name = "ghash" 689 | version = "0.5.1" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" 692 | dependencies = [ 693 | "opaque-debug", 694 | "polyval", 695 | ] 696 | 697 | [[package]] 698 | name = "glob" 699 | version = "0.3.1" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 702 | 703 | [[package]] 704 | name = "hashbrown" 705 | version = "0.14.5" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 708 | 709 | [[package]] 710 | name = "heck" 711 | version = "0.5.0" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 714 | 715 | [[package]] 716 | name = "hmac" 717 | version = "0.11.0" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" 720 | dependencies = [ 721 | "crypto-mac", 722 | "digest 0.9.0", 723 | ] 724 | 725 | [[package]] 726 | name = "home" 727 | version = "0.5.9" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 730 | dependencies = [ 731 | "windows-sys 0.52.0", 732 | ] 733 | 734 | [[package]] 735 | name = "include-flate" 736 | version = "0.2.0" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "c2e11569346406931d20276cc460215ee2826e7cad43aa986999cb244dd7adb0" 739 | dependencies = [ 740 | "include-flate-codegen-exports", 741 | "lazy_static", 742 | "libflate", 743 | ] 744 | 745 | [[package]] 746 | name = "include-flate-codegen" 747 | version = "0.1.4" 748 | source = "registry+https://github.com/rust-lang/crates.io-index" 749 | checksum = "3a7d6e1419fa3129eb0802b4c99603c0d425c79fb5d76191d5a20d0ab0d664e8" 750 | dependencies = [ 751 | "libflate", 752 | "proc-macro-hack", 753 | "proc-macro2", 754 | "quote", 755 | "syn 1.0.109", 756 | ] 757 | 758 | [[package]] 759 | name = "include-flate-codegen-exports" 760 | version = "0.1.4" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "75657043ffe3d8280f1cb8aef0f505532b392ed7758e0baeac22edadcee31a03" 763 | dependencies = [ 764 | "include-flate-codegen", 765 | "proc-macro-hack", 766 | ] 767 | 768 | [[package]] 769 | name = "indexmap" 770 | version = "2.2.6" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 773 | dependencies = [ 774 | "equivalent", 775 | "hashbrown", 776 | ] 777 | 778 | [[package]] 779 | name = "infer" 780 | version = "0.15.0" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199" 783 | dependencies = [ 784 | "cfb", 785 | ] 786 | 787 | [[package]] 788 | name = "inout" 789 | version = "0.1.3" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" 792 | dependencies = [ 793 | "generic-array", 794 | ] 795 | 796 | [[package]] 797 | name = "interprocess" 798 | version = "1.2.1" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "81f2533f3be42fffe3b5e63b71aeca416c1c3bc33e4e27be018521e76b1f38fb" 801 | dependencies = [ 802 | "blocking", 803 | "cfg-if", 804 | "futures-core", 805 | "futures-io", 806 | "intmap", 807 | "libc", 808 | "once_cell", 809 | "rustc_version", 810 | "spinning", 811 | "thiserror", 812 | "to_method", 813 | "winapi", 814 | ] 815 | 816 | [[package]] 817 | name = "intmap" 818 | version = "0.7.1" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9" 821 | 822 | [[package]] 823 | name = "is_terminal_polyfill" 824 | version = "1.70.0" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" 827 | 828 | [[package]] 829 | name = "itertools" 830 | version = "0.11.0" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" 833 | dependencies = [ 834 | "either", 835 | ] 836 | 837 | [[package]] 838 | name = "itoa" 839 | version = "1.0.11" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 842 | 843 | [[package]] 844 | name = "lazy_static" 845 | version = "1.4.0" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 848 | 849 | [[package]] 850 | name = "lazycell" 851 | version = "1.3.0" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 854 | 855 | [[package]] 856 | name = "libc" 857 | version = "0.2.155" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 860 | 861 | [[package]] 862 | name = "libflate" 863 | version = "1.4.0" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "5ff4ae71b685bbad2f2f391fe74f6b7659a34871c08b210fdc039e43bee07d18" 866 | dependencies = [ 867 | "adler32", 868 | "crc32fast", 869 | "libflate_lz77", 870 | ] 871 | 872 | [[package]] 873 | name = "libflate_lz77" 874 | version = "1.2.0" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "a52d3a8bfc85f250440e4424db7d857e241a3aebbbe301f3eb606ab15c39acbf" 877 | dependencies = [ 878 | "rle-decode-fast", 879 | ] 880 | 881 | [[package]] 882 | name = "libloading" 883 | version = "0.8.3" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" 886 | dependencies = [ 887 | "cfg-if", 888 | "windows-targets 0.52.5", 889 | ] 890 | 891 | [[package]] 892 | name = "libredox" 893 | version = "0.1.3" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 896 | dependencies = [ 897 | "bitflags 2.5.0", 898 | "libc", 899 | ] 900 | 901 | [[package]] 902 | name = "linux-raw-sys" 903 | version = "0.4.14" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 906 | 907 | [[package]] 908 | name = "lock_api" 909 | version = "0.4.12" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 912 | dependencies = [ 913 | "autocfg", 914 | "scopeguard", 915 | ] 916 | 917 | [[package]] 918 | name = "log" 919 | version = "0.4.21" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 922 | 923 | [[package]] 924 | name = "machine-uid" 925 | version = "0.5.1" 926 | source = "registry+https://github.com/rust-lang/crates.io-index" 927 | checksum = "958d2e0ee250103b08a70a5785ca5abcd077a47584b35087248a93758c699f29" 928 | dependencies = [ 929 | "bindgen 0.66.1", 930 | "cc", 931 | "winreg", 932 | ] 933 | 934 | [[package]] 935 | name = "matchers" 936 | version = "0.1.0" 937 | source = "registry+https://github.com/rust-lang/crates.io-index" 938 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 939 | dependencies = [ 940 | "regex-automata 0.1.10", 941 | ] 942 | 943 | [[package]] 944 | name = "memchr" 945 | version = "2.7.4" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 948 | 949 | [[package]] 950 | name = "memoffset" 951 | version = "0.6.5" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 954 | dependencies = [ 955 | "autocfg", 956 | ] 957 | 958 | [[package]] 959 | name = "minimal-lexical" 960 | version = "0.2.1" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 963 | 964 | [[package]] 965 | name = "nix" 966 | version = "0.23.2" 967 | source = "registry+https://github.com/rust-lang/crates.io-index" 968 | checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" 969 | dependencies = [ 970 | "bitflags 1.3.2", 971 | "cc", 972 | "cfg-if", 973 | "libc", 974 | "memoffset", 975 | ] 976 | 977 | [[package]] 978 | name = "nix" 979 | version = "0.24.3" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" 982 | dependencies = [ 983 | "bitflags 1.3.2", 984 | "cfg-if", 985 | "libc", 986 | "memoffset", 987 | ] 988 | 989 | [[package]] 990 | name = "nom" 991 | version = "7.1.3" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 994 | dependencies = [ 995 | "memchr", 996 | "minimal-lexical", 997 | ] 998 | 999 | [[package]] 1000 | name = "nu-ansi-term" 1001 | version = "0.46.0" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 1004 | dependencies = [ 1005 | "overload", 1006 | "winapi", 1007 | ] 1008 | 1009 | [[package]] 1010 | name = "num-conv" 1011 | version = "0.1.0" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1014 | 1015 | [[package]] 1016 | name = "once_cell" 1017 | version = "1.19.0" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 1020 | 1021 | [[package]] 1022 | name = "opaque-debug" 1023 | version = "0.3.1" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" 1026 | 1027 | [[package]] 1028 | name = "option-ext" 1029 | version = "0.2.0" 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" 1031 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 1032 | 1033 | [[package]] 1034 | name = "os_pipe" 1035 | version = "1.2.0" 1036 | source = "registry+https://github.com/rust-lang/crates.io-index" 1037 | checksum = "29d73ba8daf8fac13b0501d1abeddcfe21ba7401ada61a819144b6c2a4f32209" 1038 | dependencies = [ 1039 | "libc", 1040 | "windows-sys 0.52.0", 1041 | ] 1042 | 1043 | [[package]] 1044 | name = "overload" 1045 | version = "0.1.1" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1048 | 1049 | [[package]] 1050 | name = "parking" 1051 | version = "2.2.0" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" 1054 | 1055 | [[package]] 1056 | name = "paste" 1057 | version = "1.0.15" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1060 | 1061 | [[package]] 1062 | name = "pbkdf2" 1063 | version = "0.9.0" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "f05894bce6a1ba4be299d0c5f29563e08af2bc18bb7d48313113bed71e904739" 1066 | dependencies = [ 1067 | "crypto-mac", 1068 | "hmac", 1069 | "sha2 0.9.9", 1070 | ] 1071 | 1072 | [[package]] 1073 | name = "peeking_take_while" 1074 | version = "0.1.2" 1075 | source = "registry+https://github.com/rust-lang/crates.io-index" 1076 | checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" 1077 | 1078 | [[package]] 1079 | name = "petgraph" 1080 | version = "0.6.5" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" 1083 | dependencies = [ 1084 | "fixedbitset", 1085 | "indexmap", 1086 | ] 1087 | 1088 | [[package]] 1089 | name = "pin-project-lite" 1090 | version = "0.2.14" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 1093 | 1094 | [[package]] 1095 | name = "piper" 1096 | version = "0.2.3" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" 1099 | dependencies = [ 1100 | "atomic-waker", 1101 | "fastrand", 1102 | "futures-io", 1103 | ] 1104 | 1105 | [[package]] 1106 | name = "pkg-config" 1107 | version = "0.3.30" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 1110 | 1111 | [[package]] 1112 | name = "poly1305" 1113 | version = "0.8.0" 1114 | source = "registry+https://github.com/rust-lang/crates.io-index" 1115 | checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" 1116 | dependencies = [ 1117 | "cpufeatures", 1118 | "opaque-debug", 1119 | "universal-hash", 1120 | ] 1121 | 1122 | [[package]] 1123 | name = "polyval" 1124 | version = "0.6.2" 1125 | source = "registry+https://github.com/rust-lang/crates.io-index" 1126 | checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" 1127 | dependencies = [ 1128 | "cfg-if", 1129 | "cpufeatures", 1130 | "opaque-debug", 1131 | "universal-hash", 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "powerfmt" 1136 | version = "0.2.0" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1139 | 1140 | [[package]] 1141 | name = "ppv-lite86" 1142 | version = "0.2.17" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1145 | 1146 | [[package]] 1147 | name = "prettyplease" 1148 | version = "0.2.20" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" 1151 | dependencies = [ 1152 | "proc-macro2", 1153 | "syn 2.0.66", 1154 | ] 1155 | 1156 | [[package]] 1157 | name = "proc-macro-hack" 1158 | version = "0.5.20+deprecated" 1159 | source = "registry+https://github.com/rust-lang/crates.io-index" 1160 | checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" 1161 | 1162 | [[package]] 1163 | name = "proc-macro2" 1164 | version = "1.0.85" 1165 | source = "registry+https://github.com/rust-lang/crates.io-index" 1166 | checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" 1167 | dependencies = [ 1168 | "unicode-ident", 1169 | ] 1170 | 1171 | [[package]] 1172 | name = "quick-xml" 1173 | version = "0.31.0" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" 1176 | dependencies = [ 1177 | "memchr", 1178 | ] 1179 | 1180 | [[package]] 1181 | name = "quote" 1182 | version = "1.0.36" 1183 | source = "registry+https://github.com/rust-lang/crates.io-index" 1184 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 1185 | dependencies = [ 1186 | "proc-macro2", 1187 | ] 1188 | 1189 | [[package]] 1190 | name = "radium" 1191 | version = "0.7.0" 1192 | source = "registry+https://github.com/rust-lang/crates.io-index" 1193 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 1194 | 1195 | [[package]] 1196 | name = "rand" 1197 | version = "0.8.5" 1198 | source = "registry+https://github.com/rust-lang/crates.io-index" 1199 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1200 | dependencies = [ 1201 | "libc", 1202 | "rand_chacha", 1203 | "rand_core", 1204 | ] 1205 | 1206 | [[package]] 1207 | name = "rand_chacha" 1208 | version = "0.3.1" 1209 | source = "registry+https://github.com/rust-lang/crates.io-index" 1210 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1211 | dependencies = [ 1212 | "ppv-lite86", 1213 | "rand_core", 1214 | ] 1215 | 1216 | [[package]] 1217 | name = "rand_core" 1218 | version = "0.6.4" 1219 | source = "registry+https://github.com/rust-lang/crates.io-index" 1220 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1221 | dependencies = [ 1222 | "getrandom", 1223 | ] 1224 | 1225 | [[package]] 1226 | name = "redox_users" 1227 | version = "0.4.5" 1228 | source = "registry+https://github.com/rust-lang/crates.io-index" 1229 | checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" 1230 | dependencies = [ 1231 | "getrandom", 1232 | "libredox", 1233 | "thiserror", 1234 | ] 1235 | 1236 | [[package]] 1237 | name = "regex" 1238 | version = "1.10.5" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" 1241 | dependencies = [ 1242 | "aho-corasick", 1243 | "memchr", 1244 | "regex-automata 0.4.7", 1245 | "regex-syntax 0.8.4", 1246 | ] 1247 | 1248 | [[package]] 1249 | name = "regex-automata" 1250 | version = "0.1.10" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1253 | dependencies = [ 1254 | "regex-syntax 0.6.29", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "regex-automata" 1259 | version = "0.4.7" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 1262 | dependencies = [ 1263 | "aho-corasick", 1264 | "memchr", 1265 | "regex-syntax 0.8.4", 1266 | ] 1267 | 1268 | [[package]] 1269 | name = "regex-syntax" 1270 | version = "0.6.29" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 1273 | 1274 | [[package]] 1275 | name = "regex-syntax" 1276 | version = "0.8.4" 1277 | source = "registry+https://github.com/rust-lang/crates.io-index" 1278 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 1279 | 1280 | [[package]] 1281 | name = "rle-decode-fast" 1282 | version = "1.0.3" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" 1285 | 1286 | [[package]] 1287 | name = "rust-embed" 1288 | version = "8.4.0" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "19549741604902eb99a7ed0ee177a0663ee1eda51a29f71401f166e47e77806a" 1291 | dependencies = [ 1292 | "include-flate", 1293 | "rust-embed-impl", 1294 | "rust-embed-utils", 1295 | "walkdir", 1296 | ] 1297 | 1298 | [[package]] 1299 | name = "rust-embed-impl" 1300 | version = "8.4.0" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "cb9f96e283ec64401f30d3df8ee2aaeb2561f34c824381efa24a35f79bf40ee4" 1303 | dependencies = [ 1304 | "proc-macro2", 1305 | "quote", 1306 | "rust-embed-utils", 1307 | "syn 2.0.66", 1308 | "walkdir", 1309 | ] 1310 | 1311 | [[package]] 1312 | name = "rust-embed-utils" 1313 | version = "8.4.0" 1314 | source = "registry+https://github.com/rust-lang/crates.io-index" 1315 | checksum = "38c74a686185620830701348de757fd36bef4aa9680fd23c49fc539ddcc1af32" 1316 | dependencies = [ 1317 | "sha2 0.10.8", 1318 | "walkdir", 1319 | ] 1320 | 1321 | [[package]] 1322 | name = "rustc-hash" 1323 | version = "1.1.0" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1326 | 1327 | [[package]] 1328 | name = "rustc_version" 1329 | version = "0.4.0" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1332 | dependencies = [ 1333 | "semver", 1334 | ] 1335 | 1336 | [[package]] 1337 | name = "rustix" 1338 | version = "0.38.34" 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" 1340 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 1341 | dependencies = [ 1342 | "bitflags 2.5.0", 1343 | "errno", 1344 | "libc", 1345 | "linux-raw-sys", 1346 | "windows-sys 0.52.0", 1347 | ] 1348 | 1349 | [[package]] 1350 | name = "same-file" 1351 | version = "1.0.6" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1354 | dependencies = [ 1355 | "winapi-util", 1356 | ] 1357 | 1358 | [[package]] 1359 | name = "scoped-tls" 1360 | version = "1.0.1" 1361 | source = "registry+https://github.com/rust-lang/crates.io-index" 1362 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 1363 | 1364 | [[package]] 1365 | name = "scopeguard" 1366 | version = "1.2.0" 1367 | source = "registry+https://github.com/rust-lang/crates.io-index" 1368 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1369 | 1370 | [[package]] 1371 | name = "semver" 1372 | version = "1.0.23" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 1375 | 1376 | [[package]] 1377 | name = "serde" 1378 | version = "1.0.203" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" 1381 | dependencies = [ 1382 | "serde_derive", 1383 | ] 1384 | 1385 | [[package]] 1386 | name = "serde_derive" 1387 | version = "1.0.203" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" 1390 | dependencies = [ 1391 | "proc-macro2", 1392 | "quote", 1393 | "syn 2.0.66", 1394 | ] 1395 | 1396 | [[package]] 1397 | name = "serde_spanned" 1398 | version = "0.6.6" 1399 | source = "registry+https://github.com/rust-lang/crates.io-index" 1400 | checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" 1401 | dependencies = [ 1402 | "serde", 1403 | ] 1404 | 1405 | [[package]] 1406 | name = "sha2" 1407 | version = "0.9.9" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 1410 | dependencies = [ 1411 | "block-buffer 0.9.0", 1412 | "cfg-if", 1413 | "cpufeatures", 1414 | "digest 0.9.0", 1415 | "opaque-debug", 1416 | ] 1417 | 1418 | [[package]] 1419 | name = "sha2" 1420 | version = "0.10.8" 1421 | source = "registry+https://github.com/rust-lang/crates.io-index" 1422 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1423 | dependencies = [ 1424 | "cfg-if", 1425 | "cpufeatures", 1426 | "digest 0.10.7", 1427 | ] 1428 | 1429 | [[package]] 1430 | name = "sharded-slab" 1431 | version = "0.1.7" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1434 | dependencies = [ 1435 | "lazy_static", 1436 | ] 1437 | 1438 | [[package]] 1439 | name = "shlex" 1440 | version = "1.3.0" 1441 | source = "registry+https://github.com/rust-lang/crates.io-index" 1442 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1443 | 1444 | [[package]] 1445 | name = "smallvec" 1446 | version = "1.13.2" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1449 | 1450 | [[package]] 1451 | name = "spinning" 1452 | version = "0.1.0" 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" 1454 | checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b" 1455 | dependencies = [ 1456 | "lock_api", 1457 | ] 1458 | 1459 | [[package]] 1460 | name = "strsim" 1461 | version = "0.11.1" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1464 | 1465 | [[package]] 1466 | name = "subtle" 1467 | version = "2.4.1" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1470 | 1471 | [[package]] 1472 | name = "syn" 1473 | version = "1.0.109" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1476 | dependencies = [ 1477 | "proc-macro2", 1478 | "quote", 1479 | "unicode-ident", 1480 | ] 1481 | 1482 | [[package]] 1483 | name = "syn" 1484 | version = "2.0.66" 1485 | source = "registry+https://github.com/rust-lang/crates.io-index" 1486 | checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" 1487 | dependencies = [ 1488 | "proc-macro2", 1489 | "quote", 1490 | "unicode-ident", 1491 | ] 1492 | 1493 | [[package]] 1494 | name = "tap" 1495 | version = "1.0.1" 1496 | source = "registry+https://github.com/rust-lang/crates.io-index" 1497 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 1498 | 1499 | [[package]] 1500 | name = "tempfile" 1501 | version = "3.10.1" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 1504 | dependencies = [ 1505 | "cfg-if", 1506 | "fastrand", 1507 | "rustix", 1508 | "windows-sys 0.52.0", 1509 | ] 1510 | 1511 | [[package]] 1512 | name = "thiserror" 1513 | version = "1.0.61" 1514 | source = "registry+https://github.com/rust-lang/crates.io-index" 1515 | checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" 1516 | dependencies = [ 1517 | "thiserror-impl", 1518 | ] 1519 | 1520 | [[package]] 1521 | name = "thiserror-impl" 1522 | version = "1.0.61" 1523 | source = "registry+https://github.com/rust-lang/crates.io-index" 1524 | checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" 1525 | dependencies = [ 1526 | "proc-macro2", 1527 | "quote", 1528 | "syn 2.0.66", 1529 | ] 1530 | 1531 | [[package]] 1532 | name = "thread_local" 1533 | version = "1.1.8" 1534 | source = "registry+https://github.com/rust-lang/crates.io-index" 1535 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 1536 | dependencies = [ 1537 | "cfg-if", 1538 | "once_cell", 1539 | ] 1540 | 1541 | [[package]] 1542 | name = "time" 1543 | version = "0.3.36" 1544 | source = "registry+https://github.com/rust-lang/crates.io-index" 1545 | checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" 1546 | dependencies = [ 1547 | "deranged", 1548 | "itoa", 1549 | "num-conv", 1550 | "powerfmt", 1551 | "serde", 1552 | "time-core", 1553 | "time-macros", 1554 | ] 1555 | 1556 | [[package]] 1557 | name = "time-core" 1558 | version = "0.1.2" 1559 | source = "registry+https://github.com/rust-lang/crates.io-index" 1560 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 1561 | 1562 | [[package]] 1563 | name = "time-macros" 1564 | version = "0.2.18" 1565 | source = "registry+https://github.com/rust-lang/crates.io-index" 1566 | checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" 1567 | dependencies = [ 1568 | "num-conv", 1569 | "time-core", 1570 | ] 1571 | 1572 | [[package]] 1573 | name = "to_method" 1574 | version = "1.1.0" 1575 | source = "registry+https://github.com/rust-lang/crates.io-index" 1576 | checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8" 1577 | 1578 | [[package]] 1579 | name = "toml" 1580 | version = "0.8.14" 1581 | source = "registry+https://github.com/rust-lang/crates.io-index" 1582 | checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" 1583 | dependencies = [ 1584 | "serde", 1585 | "serde_spanned", 1586 | "toml_datetime", 1587 | "toml_edit", 1588 | ] 1589 | 1590 | [[package]] 1591 | name = "toml_datetime" 1592 | version = "0.6.6" 1593 | source = "registry+https://github.com/rust-lang/crates.io-index" 1594 | checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" 1595 | dependencies = [ 1596 | "serde", 1597 | ] 1598 | 1599 | [[package]] 1600 | name = "toml_edit" 1601 | version = "0.22.14" 1602 | source = "registry+https://github.com/rust-lang/crates.io-index" 1603 | checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" 1604 | dependencies = [ 1605 | "indexmap", 1606 | "serde", 1607 | "serde_spanned", 1608 | "toml_datetime", 1609 | "winnow", 1610 | ] 1611 | 1612 | [[package]] 1613 | name = "tracing" 1614 | version = "0.1.40" 1615 | source = "registry+https://github.com/rust-lang/crates.io-index" 1616 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 1617 | dependencies = [ 1618 | "pin-project-lite", 1619 | "tracing-attributes", 1620 | "tracing-core", 1621 | ] 1622 | 1623 | [[package]] 1624 | name = "tracing-appender" 1625 | version = "0.2.3" 1626 | source = "registry+https://github.com/rust-lang/crates.io-index" 1627 | checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" 1628 | dependencies = [ 1629 | "crossbeam-channel", 1630 | "thiserror", 1631 | "time", 1632 | "tracing-subscriber", 1633 | ] 1634 | 1635 | [[package]] 1636 | name = "tracing-attributes" 1637 | version = "0.1.27" 1638 | source = "registry+https://github.com/rust-lang/crates.io-index" 1639 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 1640 | dependencies = [ 1641 | "proc-macro2", 1642 | "quote", 1643 | "syn 2.0.66", 1644 | ] 1645 | 1646 | [[package]] 1647 | name = "tracing-core" 1648 | version = "0.1.32" 1649 | source = "registry+https://github.com/rust-lang/crates.io-index" 1650 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 1651 | dependencies = [ 1652 | "once_cell", 1653 | "valuable", 1654 | ] 1655 | 1656 | [[package]] 1657 | name = "tracing-log" 1658 | version = "0.2.0" 1659 | source = "registry+https://github.com/rust-lang/crates.io-index" 1660 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 1661 | dependencies = [ 1662 | "log", 1663 | "once_cell", 1664 | "tracing-core", 1665 | ] 1666 | 1667 | [[package]] 1668 | name = "tracing-subscriber" 1669 | version = "0.3.18" 1670 | source = "registry+https://github.com/rust-lang/crates.io-index" 1671 | checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" 1672 | dependencies = [ 1673 | "matchers", 1674 | "nu-ansi-term", 1675 | "once_cell", 1676 | "regex", 1677 | "sharded-slab", 1678 | "smallvec", 1679 | "thread_local", 1680 | "tracing", 1681 | "tracing-core", 1682 | "tracing-log", 1683 | ] 1684 | 1685 | [[package]] 1686 | name = "tree_magic_mini" 1687 | version = "3.1.5" 1688 | source = "registry+https://github.com/rust-lang/crates.io-index" 1689 | checksum = "469a727cac55b41448315cc10427c069c618ac59bb6a4480283fcd811749bdc2" 1690 | dependencies = [ 1691 | "fnv", 1692 | "home", 1693 | "memchr", 1694 | "nom", 1695 | "once_cell", 1696 | "petgraph", 1697 | ] 1698 | 1699 | [[package]] 1700 | name = "typenum" 1701 | version = "1.17.0" 1702 | source = "registry+https://github.com/rust-lang/crates.io-index" 1703 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1704 | 1705 | [[package]] 1706 | name = "uncased" 1707 | version = "0.9.10" 1708 | source = "registry+https://github.com/rust-lang/crates.io-index" 1709 | checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" 1710 | dependencies = [ 1711 | "version_check", 1712 | ] 1713 | 1714 | [[package]] 1715 | name = "unicode-ident" 1716 | version = "1.0.12" 1717 | source = "registry+https://github.com/rust-lang/crates.io-index" 1718 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1719 | 1720 | [[package]] 1721 | name = "universal-hash" 1722 | version = "0.5.1" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" 1725 | dependencies = [ 1726 | "crypto-common", 1727 | "subtle", 1728 | ] 1729 | 1730 | [[package]] 1731 | name = "utf8parse" 1732 | version = "0.2.2" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1735 | 1736 | [[package]] 1737 | name = "uuid" 1738 | version = "1.8.0" 1739 | source = "registry+https://github.com/rust-lang/crates.io-index" 1740 | checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" 1741 | 1742 | [[package]] 1743 | name = "valuable" 1744 | version = "0.1.0" 1745 | source = "registry+https://github.com/rust-lang/crates.io-index" 1746 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 1747 | 1748 | [[package]] 1749 | name = "version_check" 1750 | version = "0.9.4" 1751 | source = "registry+https://github.com/rust-lang/crates.io-index" 1752 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1753 | 1754 | [[package]] 1755 | name = "walkdir" 1756 | version = "2.5.0" 1757 | source = "registry+https://github.com/rust-lang/crates.io-index" 1758 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 1759 | dependencies = [ 1760 | "same-file", 1761 | "winapi-util", 1762 | ] 1763 | 1764 | [[package]] 1765 | name = "wasi" 1766 | version = "0.11.0+wasi-snapshot-preview1" 1767 | source = "registry+https://github.com/rust-lang/crates.io-index" 1768 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1769 | 1770 | [[package]] 1771 | name = "wayclip" 1772 | version = "0.4.1" 1773 | dependencies = [ 1774 | "bincode", 1775 | "bindgen 0.68.1", 1776 | "clap", 1777 | "cocoon", 1778 | "dirs", 1779 | "evdev", 1780 | "figment", 1781 | "infer", 1782 | "interprocess", 1783 | "itertools", 1784 | "machine-uid", 1785 | "os_pipe", 1786 | "quote", 1787 | "rand", 1788 | "rust-embed", 1789 | "serde", 1790 | "tracing", 1791 | "tracing-appender", 1792 | "tracing-subscriber", 1793 | "wayland-client 0.31.3", 1794 | "wayland-protocols 0.31.2", 1795 | "wayland-protocols-wlr", 1796 | "wl-clipboard-rs", 1797 | ] 1798 | 1799 | [[package]] 1800 | name = "wayland-backend" 1801 | version = "0.3.4" 1802 | source = "registry+https://github.com/rust-lang/crates.io-index" 1803 | checksum = "34e9e6b6d4a2bb4e7e69433e0b35c7923b95d4dc8503a84d25ec917a4bbfdf07" 1804 | dependencies = [ 1805 | "cc", 1806 | "downcast-rs", 1807 | "rustix", 1808 | "scoped-tls", 1809 | "smallvec", 1810 | "wayland-sys 0.31.2", 1811 | ] 1812 | 1813 | [[package]] 1814 | name = "wayland-client" 1815 | version = "0.29.5" 1816 | source = "registry+https://github.com/rust-lang/crates.io-index" 1817 | checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" 1818 | dependencies = [ 1819 | "bitflags 1.3.2", 1820 | "downcast-rs", 1821 | "libc", 1822 | "nix 0.24.3", 1823 | "wayland-commons", 1824 | "wayland-scanner 0.29.5", 1825 | "wayland-sys 0.29.5", 1826 | ] 1827 | 1828 | [[package]] 1829 | name = "wayland-client" 1830 | version = "0.31.3" 1831 | source = "registry+https://github.com/rust-lang/crates.io-index" 1832 | checksum = "1e63801c85358a431f986cffa74ba9599ff571fc5774ac113ed3b490c19a1133" 1833 | dependencies = [ 1834 | "bitflags 2.5.0", 1835 | "rustix", 1836 | "wayland-backend", 1837 | "wayland-scanner 0.31.2", 1838 | ] 1839 | 1840 | [[package]] 1841 | name = "wayland-commons" 1842 | version = "0.29.5" 1843 | source = "registry+https://github.com/rust-lang/crates.io-index" 1844 | checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" 1845 | dependencies = [ 1846 | "nix 0.24.3", 1847 | "once_cell", 1848 | "smallvec", 1849 | "wayland-sys 0.29.5", 1850 | ] 1851 | 1852 | [[package]] 1853 | name = "wayland-protocols" 1854 | version = "0.29.5" 1855 | source = "registry+https://github.com/rust-lang/crates.io-index" 1856 | checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" 1857 | dependencies = [ 1858 | "bitflags 1.3.2", 1859 | "wayland-client 0.29.5", 1860 | "wayland-commons", 1861 | "wayland-scanner 0.29.5", 1862 | ] 1863 | 1864 | [[package]] 1865 | name = "wayland-protocols" 1866 | version = "0.31.2" 1867 | source = "registry+https://github.com/rust-lang/crates.io-index" 1868 | checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" 1869 | dependencies = [ 1870 | "bitflags 2.5.0", 1871 | "wayland-backend", 1872 | "wayland-client 0.31.3", 1873 | "wayland-scanner 0.31.2", 1874 | ] 1875 | 1876 | [[package]] 1877 | name = "wayland-protocols-wlr" 1878 | version = "0.2.0" 1879 | source = "registry+https://github.com/rust-lang/crates.io-index" 1880 | checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" 1881 | dependencies = [ 1882 | "bitflags 2.5.0", 1883 | "wayland-backend", 1884 | "wayland-client 0.31.3", 1885 | "wayland-protocols 0.31.2", 1886 | "wayland-scanner 0.31.2", 1887 | ] 1888 | 1889 | [[package]] 1890 | name = "wayland-scanner" 1891 | version = "0.29.5" 1892 | source = "registry+https://github.com/rust-lang/crates.io-index" 1893 | checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" 1894 | dependencies = [ 1895 | "proc-macro2", 1896 | "quote", 1897 | "xml-rs", 1898 | ] 1899 | 1900 | [[package]] 1901 | name = "wayland-scanner" 1902 | version = "0.31.2" 1903 | source = "registry+https://github.com/rust-lang/crates.io-index" 1904 | checksum = "67da50b9f80159dec0ea4c11c13e24ef9e7574bd6ce24b01860a175010cea565" 1905 | dependencies = [ 1906 | "proc-macro2", 1907 | "quick-xml", 1908 | "quote", 1909 | ] 1910 | 1911 | [[package]] 1912 | name = "wayland-sys" 1913 | version = "0.29.5" 1914 | source = "registry+https://github.com/rust-lang/crates.io-index" 1915 | checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" 1916 | dependencies = [ 1917 | "pkg-config", 1918 | ] 1919 | 1920 | [[package]] 1921 | name = "wayland-sys" 1922 | version = "0.31.2" 1923 | source = "registry+https://github.com/rust-lang/crates.io-index" 1924 | checksum = "105b1842da6554f91526c14a2a2172897b7f745a805d62af4ce698706be79c12" 1925 | dependencies = [ 1926 | "dlib", 1927 | "log", 1928 | "pkg-config", 1929 | ] 1930 | 1931 | [[package]] 1932 | name = "which" 1933 | version = "4.4.2" 1934 | source = "registry+https://github.com/rust-lang/crates.io-index" 1935 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 1936 | dependencies = [ 1937 | "either", 1938 | "home", 1939 | "once_cell", 1940 | "rustix", 1941 | ] 1942 | 1943 | [[package]] 1944 | name = "winapi" 1945 | version = "0.3.9" 1946 | source = "registry+https://github.com/rust-lang/crates.io-index" 1947 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1948 | dependencies = [ 1949 | "winapi-i686-pc-windows-gnu", 1950 | "winapi-x86_64-pc-windows-gnu", 1951 | ] 1952 | 1953 | [[package]] 1954 | name = "winapi-i686-pc-windows-gnu" 1955 | version = "0.4.0" 1956 | source = "registry+https://github.com/rust-lang/crates.io-index" 1957 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1958 | 1959 | [[package]] 1960 | name = "winapi-util" 1961 | version = "0.1.8" 1962 | source = "registry+https://github.com/rust-lang/crates.io-index" 1963 | checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" 1964 | dependencies = [ 1965 | "windows-sys 0.52.0", 1966 | ] 1967 | 1968 | [[package]] 1969 | name = "winapi-x86_64-pc-windows-gnu" 1970 | version = "0.4.0" 1971 | source = "registry+https://github.com/rust-lang/crates.io-index" 1972 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1973 | 1974 | [[package]] 1975 | name = "windows-sys" 1976 | version = "0.48.0" 1977 | source = "registry+https://github.com/rust-lang/crates.io-index" 1978 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1979 | dependencies = [ 1980 | "windows-targets 0.48.5", 1981 | ] 1982 | 1983 | [[package]] 1984 | name = "windows-sys" 1985 | version = "0.52.0" 1986 | source = "registry+https://github.com/rust-lang/crates.io-index" 1987 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1988 | dependencies = [ 1989 | "windows-targets 0.52.5", 1990 | ] 1991 | 1992 | [[package]] 1993 | name = "windows-targets" 1994 | version = "0.48.5" 1995 | source = "registry+https://github.com/rust-lang/crates.io-index" 1996 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1997 | dependencies = [ 1998 | "windows_aarch64_gnullvm 0.48.5", 1999 | "windows_aarch64_msvc 0.48.5", 2000 | "windows_i686_gnu 0.48.5", 2001 | "windows_i686_msvc 0.48.5", 2002 | "windows_x86_64_gnu 0.48.5", 2003 | "windows_x86_64_gnullvm 0.48.5", 2004 | "windows_x86_64_msvc 0.48.5", 2005 | ] 2006 | 2007 | [[package]] 2008 | name = "windows-targets" 2009 | version = "0.52.5" 2010 | source = "registry+https://github.com/rust-lang/crates.io-index" 2011 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" 2012 | dependencies = [ 2013 | "windows_aarch64_gnullvm 0.52.5", 2014 | "windows_aarch64_msvc 0.52.5", 2015 | "windows_i686_gnu 0.52.5", 2016 | "windows_i686_gnullvm", 2017 | "windows_i686_msvc 0.52.5", 2018 | "windows_x86_64_gnu 0.52.5", 2019 | "windows_x86_64_gnullvm 0.52.5", 2020 | "windows_x86_64_msvc 0.52.5", 2021 | ] 2022 | 2023 | [[package]] 2024 | name = "windows_aarch64_gnullvm" 2025 | version = "0.48.5" 2026 | source = "registry+https://github.com/rust-lang/crates.io-index" 2027 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2028 | 2029 | [[package]] 2030 | name = "windows_aarch64_gnullvm" 2031 | version = "0.52.5" 2032 | source = "registry+https://github.com/rust-lang/crates.io-index" 2033 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" 2034 | 2035 | [[package]] 2036 | name = "windows_aarch64_msvc" 2037 | version = "0.48.5" 2038 | source = "registry+https://github.com/rust-lang/crates.io-index" 2039 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2040 | 2041 | [[package]] 2042 | name = "windows_aarch64_msvc" 2043 | version = "0.52.5" 2044 | source = "registry+https://github.com/rust-lang/crates.io-index" 2045 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" 2046 | 2047 | [[package]] 2048 | name = "windows_i686_gnu" 2049 | version = "0.48.5" 2050 | source = "registry+https://github.com/rust-lang/crates.io-index" 2051 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2052 | 2053 | [[package]] 2054 | name = "windows_i686_gnu" 2055 | version = "0.52.5" 2056 | source = "registry+https://github.com/rust-lang/crates.io-index" 2057 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" 2058 | 2059 | [[package]] 2060 | name = "windows_i686_gnullvm" 2061 | version = "0.52.5" 2062 | source = "registry+https://github.com/rust-lang/crates.io-index" 2063 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" 2064 | 2065 | [[package]] 2066 | name = "windows_i686_msvc" 2067 | version = "0.48.5" 2068 | source = "registry+https://github.com/rust-lang/crates.io-index" 2069 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2070 | 2071 | [[package]] 2072 | name = "windows_i686_msvc" 2073 | version = "0.52.5" 2074 | source = "registry+https://github.com/rust-lang/crates.io-index" 2075 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" 2076 | 2077 | [[package]] 2078 | name = "windows_x86_64_gnu" 2079 | version = "0.48.5" 2080 | source = "registry+https://github.com/rust-lang/crates.io-index" 2081 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2082 | 2083 | [[package]] 2084 | name = "windows_x86_64_gnu" 2085 | version = "0.52.5" 2086 | source = "registry+https://github.com/rust-lang/crates.io-index" 2087 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" 2088 | 2089 | [[package]] 2090 | name = "windows_x86_64_gnullvm" 2091 | version = "0.48.5" 2092 | source = "registry+https://github.com/rust-lang/crates.io-index" 2093 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2094 | 2095 | [[package]] 2096 | name = "windows_x86_64_gnullvm" 2097 | version = "0.52.5" 2098 | source = "registry+https://github.com/rust-lang/crates.io-index" 2099 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" 2100 | 2101 | [[package]] 2102 | name = "windows_x86_64_msvc" 2103 | version = "0.48.5" 2104 | source = "registry+https://github.com/rust-lang/crates.io-index" 2105 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2106 | 2107 | [[package]] 2108 | name = "windows_x86_64_msvc" 2109 | version = "0.52.5" 2110 | source = "registry+https://github.com/rust-lang/crates.io-index" 2111 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" 2112 | 2113 | [[package]] 2114 | name = "winnow" 2115 | version = "0.6.13" 2116 | source = "registry+https://github.com/rust-lang/crates.io-index" 2117 | checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" 2118 | dependencies = [ 2119 | "memchr", 2120 | ] 2121 | 2122 | [[package]] 2123 | name = "winreg" 2124 | version = "0.50.0" 2125 | source = "registry+https://github.com/rust-lang/crates.io-index" 2126 | checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" 2127 | dependencies = [ 2128 | "cfg-if", 2129 | "windows-sys 0.48.0", 2130 | ] 2131 | 2132 | [[package]] 2133 | name = "wl-clipboard-rs" 2134 | version = "0.7.0" 2135 | source = "registry+https://github.com/rust-lang/crates.io-index" 2136 | checksum = "981a303dfbb75d659f6612d05a14b2e363c103d24f676a2d44a00d18507a1ad9" 2137 | dependencies = [ 2138 | "derive-new", 2139 | "libc", 2140 | "log", 2141 | "nix 0.24.3", 2142 | "os_pipe", 2143 | "tempfile", 2144 | "thiserror", 2145 | "tree_magic_mini", 2146 | "wayland-client 0.29.5", 2147 | "wayland-protocols 0.29.5", 2148 | ] 2149 | 2150 | [[package]] 2151 | name = "wyz" 2152 | version = "0.5.1" 2153 | source = "registry+https://github.com/rust-lang/crates.io-index" 2154 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 2155 | dependencies = [ 2156 | "tap", 2157 | ] 2158 | 2159 | [[package]] 2160 | name = "xml-rs" 2161 | version = "0.8.20" 2162 | source = "registry+https://github.com/rust-lang/crates.io-index" 2163 | checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" 2164 | 2165 | [[package]] 2166 | name = "zeroize" 2167 | version = "1.8.1" 2168 | source = "registry+https://github.com/rust-lang/crates.io-index" 2169 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2170 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wayclip" 3 | version = "0.4.1" 4 | authors = ["Joey Eamigh"] 5 | edition = "2021" 6 | rust-version = "1.75" 7 | description = "An opinionated Wayland clipboard manager" 8 | repository = "https://github.com/JoeyEamigh/wayclip.git" 9 | documentation = "https://github.com/JoeyEamigh/wayclip" 10 | homepage = "https://github.com/JoeyEamigh/wayclip" 11 | keywords = ["wayland", "clipboard", "manager"] 12 | readme = "README.md" 13 | license = "MIT" 14 | 15 | [dependencies] 16 | bincode = "1.3.3" 17 | clap = { version = "4.5.7", features = ["derive"] } 18 | cocoon = "0.3.3" 19 | dirs = "5.0.1" 20 | evdev = { version = "0.12.2", features = ["paste"] } 21 | figment = { version = "0.10.19", features = ["toml"] } 22 | infer = "0.15.0" 23 | interprocess = "1.2.1" 24 | itertools = "0.11.0" 25 | machine-uid = "0.5.1" 26 | os_pipe = "1.2.0" 27 | quote = "1.0.36" 28 | rand = "0.8.5" 29 | rust-embed = { version = "8.4.0", features = ["compression"] } 30 | serde = { version = "1.0.203", features = ["derive"] } 31 | tracing = "0.1.40" 32 | tracing-appender = "0.2.3" 33 | tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } 34 | wayland-client = "0.31.3" 35 | wayland-protocols = { version = "0.31.2", features = ["client", "unstable"] } 36 | wayland-protocols-wlr = { version = "0.2.0", features = ["client"] } 37 | wl-clipboard-rs = "0.7.0" 38 | 39 | [build-dependencies] 40 | bindgen = "0.68.1" 41 | 42 | [features] 43 | default = ["bemenu"] 44 | bemenu = [] 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Joey Eamigh 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 | # wayclip: an opinionated Wayland clipboard manager (for kde and sway at the moment) 2 | 3 | wayclip is a clipboard manager for Wayland compositors. It is written in Rust and monitors the clipboard by interfacing with zwlr_data_control_manager_v1. this means it works on KWin and Sway for the moment. 4 | 5 | ## Features 6 | 7 | - text clipboard history 8 | - selection of history items with bemenu 9 | - history persistence 10 | - history item limit 11 | - history encryption 12 | 13 | ## Dependencies 14 | 15 | wayclip depends on the following in version 1: 16 | 17 | - bemenu 18 | 19 | ## Installation 20 | 21 | wayclip needs access to the `input` user group to paste since the wayland virtual keyboard protocol has spotty support (and i use kde). 22 | 23 | to add your user to the input group run: 24 | 25 | ```bash 26 | sudo gpasswd -a $USER input 27 | ``` 28 | 29 | then log out and back in, or reboot. 30 | 31 | ### From source 32 | 33 | ```bash 34 | git clone https://github.com/JoeyEamigh/wayclip.git 35 | cd wayclip 36 | 37 | cargo build --release 38 | ./install.sh // installs to /usr/local/bin and requires sudo 39 | 40 | wayclip install // installs systemd file 41 | ``` 42 | 43 | ### Arch Linux AUR 44 | 45 | ```bash 46 | paru -S wayclip-manager-git 47 | yay -S wayclip-manager-git 48 | 49 | wayclip install // installs systemd file 50 | ``` 51 | 52 | ### Cargo 53 | 54 | ```bash 55 | cargo install wayclip 56 | 57 | wayclip install // installs systemd file 58 | ``` 59 | 60 | ## Config 61 | 62 | the config file for wayclip will be created after first run and lives at `~/.config/wayclip/config.toml`. most of the options work, but some are works in progress. 63 | 64 | ## Usage 65 | 66 | wayclip is a daemon that monitors the clipboard. when you run `wayclip install`, it installs a user systemd file which can be enabled with `systemctl --user enable wayclip.service` and started with `systemctl --user start wayclip.service`. 67 | 68 | since wayland has no working hotkeys system, you should use your compositor's hotkey system to start wayclip. for example, in kde 5.27, open the shortcuts setting panel, and click `add command`. type `wayclip toggle` in the prompt box, then bind it to your preferred shortcut. 69 | 70 | ## TODO (not sure how much of this i will actually do) 71 | 72 | - [x] add an actual dedupe 73 | - [ ] add support for multiple text mime-types at a time 74 | - [ ] add support for images 75 | - [ ] add support for files 76 | - [ ] add support for other compositors and wayland protocols (ongoing) 77 | - [ ] add support for other menu programs (dmenu, rofi, etc.) 78 | -------------------------------------------------------------------------------- /bindings/bemenu.h: -------------------------------------------------------------------------------- 1 | #include -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | #![feature(stmt_expr_attributes)] 2 | extern crate bindgen; 3 | 4 | use std::env; 5 | use std::path::PathBuf; 6 | 7 | fn main() { 8 | println!("cargo:rustc-link-search=/usr/lib"); 9 | 10 | let mut builder = bindgen::Builder::default(); 11 | 12 | #[cfg(feature = "bemenu")] 13 | builder = bemenu(builder); 14 | 15 | let bindings = builder 16 | .parse_callbacks(Box::new(bindgen::CargoCallbacks)) 17 | .generate() 18 | .expect("Unable to generate bindings"); 19 | 20 | let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); 21 | bindings 22 | .write_to_file(out_path.join("bindings.rs")) 23 | .expect("Couldn't write bindings!"); 24 | } 25 | 26 | fn bemenu(builder: bindgen::Builder) -> bindgen::Builder { 27 | println!("cargo:rustc-link-lib=bemenu"); 28 | println!("cargo:rerun-if-changed=bindings/bemenu.h"); 29 | 30 | builder.header("bindings/bemenu.h") 31 | } 32 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PACKAGE=wayclip 4 | 5 | cargo build --release 6 | 7 | systemctl --user stop wayclip.service 8 | sudo cp target/release/$PACKAGE /usr/local/bin/$PACKAGE 9 | -------------------------------------------------------------------------------- /resources/config.toml: -------------------------------------------------------------------------------- 1 | [general] 2 | maxHistory = 0 # maximum number of history entries to keep (set to 0 to disable) 3 | menu = 'bemenu' # only bemenu is supported at the moment 4 | allowImages = false # whether to allow images to be copied to the clipboard (can be slow) 5 | 6 | [data] 7 | mime = 'text/plain' # preferred mime type to use when copying text 8 | dedupe = true # whether to deduplicate history entries 9 | 10 | [encryption] 11 | encrypt = true # whether to encrypt the history file 12 | key = '' # encryption key (leave blank to use the default key) 13 | 14 | [bemenu] 15 | font = 'monospace 12' # format is '"font name" size' 16 | title = 'search >' # title of the bemenu window (essentially a prompt) 17 | lines = 15 # number of lines to show in the bemenu window 18 | grabFocus = true # whether to grab focus when the bemenu window is shown 19 | monitor = -1 # monitor to show the bemenu window on (-1 means the currently focused monitor) 20 | -------------------------------------------------------------------------------- /resources/wayclip.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=wayclip: An opinionated Wayland clipboard manager 3 | PartOf=graphical-session.target 4 | After=graphical-session.target 5 | Requisite=graphical-session.target 6 | 7 | [Service] 8 | Type=simple 9 | ExecStart=wayclip 10 | Restart=always 11 | 12 | [Install] 13 | WantedBy=graphical-session.target -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" -------------------------------------------------------------------------------- /src/clipboard/mod.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, RwLock}; 2 | 3 | use crate::config::{data::Config, file::FileHelper}; 4 | use serde::{Deserialize, Serialize}; 5 | use tracing::{debug, trace}; 6 | use wayland_client::backend::ObjectId; 7 | 8 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 9 | pub struct TextItem { 10 | pub text: String, 11 | pub mime: String, 12 | } 13 | 14 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 15 | pub struct ImageItem { 16 | pub image: Vec, 17 | pub mime: String, 18 | } 19 | 20 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 21 | pub enum ItemData { 22 | Text(TextItem), 23 | Image(ImageItem), 24 | } 25 | 26 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 27 | pub struct Item { 28 | pub id: String, 29 | pub data: ItemData, 30 | } 31 | 32 | #[derive(Clone, Debug)] 33 | pub struct LiveClipboard { 34 | pub id: ObjectId, 35 | pub offer: 36 | Option, 37 | pub mime_types: Vec, 38 | pub data: Vec, 39 | pub instant: std::time::Instant, 40 | } 41 | 42 | impl LiveClipboard { 43 | pub fn new(id: ObjectId) -> Self { 44 | LiveClipboard { 45 | id, 46 | offer: None, 47 | mime_types: vec![], 48 | data: vec![], 49 | instant: std::time::Instant::now(), 50 | } 51 | } 52 | 53 | pub fn handle_offer( 54 | &mut self, 55 | offer: &wayland_protocols_wlr::data_control::v1::client::zwlr_data_control_offer_v1::ZwlrDataControlOfferV1, 56 | mime_type: String, 57 | ) { 58 | self.mime_types.push(mime_type); 59 | 60 | if self.offer.is_none() { 61 | self.offer = Some(offer.clone()); 62 | } 63 | } 64 | } 65 | 66 | #[derive(Clone, Debug)] 67 | pub struct Clipboard { 68 | pub live: Option, 69 | pub hist: Vec, 70 | 71 | // private 72 | config: Config, 73 | helper: FileHelper, 74 | } 75 | 76 | pub type WrappedClipboard = Arc>; 77 | 78 | impl Clipboard { 79 | pub fn init(config: Config, helper: FileHelper) -> WrappedClipboard { 80 | let mut cb = Clipboard { 81 | live: None, 82 | hist: vec![], 83 | 84 | // private 85 | config, 86 | helper, 87 | }; 88 | 89 | cb.restore(); 90 | 91 | Arc::new(RwLock::new(cb)) 92 | } 93 | 94 | pub fn new_offer(&mut self, id: ObjectId) { 95 | self.live = Some(LiveClipboard::new(id)); 96 | } 97 | 98 | pub fn commit(&mut self, data: Item) { 99 | if let Some(last) = self.hist.last() { 100 | match (last.clone().data, data.clone().data) { 101 | (ItemData::Text(text), ItemData::Text(new_text)) if text.text == new_text.text => return, 102 | (ItemData::Image(image), ItemData::Image(new_image)) if image.image == new_image.image => return, 103 | _ => {} 104 | } 105 | } 106 | 107 | if self.config.data.dedupe { 108 | let timer = std::time::Instant::now(); 109 | 110 | let idx = self 111 | .hist 112 | .iter() 113 | .position(|item| match (item.clone().data, data.clone().data) { 114 | (ItemData::Text(text), ItemData::Text(new_text)) if text.text == new_text.text => true, 115 | (ItemData::Image(image), ItemData::Image(new_image)) if image.image == new_image.image => true, 116 | _ => false, 117 | }); 118 | 119 | if let Some(idx) = idx { 120 | debug!("found duplicate clipboard item - removing"); 121 | self.hist.remove(idx); 122 | } 123 | 124 | trace!("(copy function) deduped clipboard in {:?}", timer.elapsed()); 125 | } 126 | 127 | self.hist.push(data); 128 | if self.hist.len() > self.config.general.max_history && self.config.general.max_history > 0 { 129 | self.hist.remove(0); 130 | } 131 | 132 | self.live = None; 133 | self.save(); 134 | } 135 | 136 | pub fn preferred_text_mime(&self) -> String { 137 | self.config.data.mime.to_string() 138 | } 139 | 140 | pub fn get_config(&self) -> Config { 141 | self.config.clone() 142 | } 143 | 144 | pub fn dump(&self) { 145 | println!("{:#?}", self.hist); 146 | } 147 | 148 | pub fn clear(&mut self) { 149 | self.hist.clear(); 150 | self.save() 151 | } 152 | 153 | /// handle a clipboard paste event by moving the selected index to the end 154 | pub fn pasted_idx(&mut self, idx: usize) { 155 | if idx >= self.hist.len() { 156 | return; 157 | } 158 | 159 | // remove the item from history reversed 160 | let item = self.hist.remove(self.hist.len() - idx - 1); 161 | self.hist.push(item); 162 | self.save(); 163 | } 164 | 165 | fn save(&self) { 166 | let timer = std::time::Instant::now(); 167 | 168 | let savable = self.hist.clone(); 169 | 170 | debug!("persisting {:?} clipboard items", savable.len()); 171 | self.helper.persist_clipboard(savable); 172 | 173 | trace!("persisted clipboard in {:?}", timer.elapsed()); 174 | } 175 | 176 | fn restore(&mut self) { 177 | let timer = std::time::Instant::now(); 178 | 179 | let existing = self.helper.retrieve_clipboard(); 180 | 181 | if let Some(mut existing) = existing { 182 | if !self.config.general.allow_images { 183 | let timer = std::time::Instant::now(); 184 | 185 | existing.retain(|item| match item.data.clone() { 186 | ItemData::Text(_) => true, 187 | ItemData::Image(_) => false, 188 | }); 189 | 190 | trace!("(restore function) image removal took {:?}", timer.elapsed()); 191 | } 192 | 193 | if !self.config.data.dedupe { 194 | self.hist = existing; 195 | } else { 196 | use itertools::Itertools; 197 | 198 | let timer = std::time::Instant::now(); 199 | 200 | self.hist = existing 201 | .into_iter() 202 | .unique_by(|item| match item.data.clone() { 203 | ItemData::Text(text) => text.text, 204 | // no good way to dedupe images with unique_by bc of clones - hashing maybe but that's a lot of work 205 | ItemData::Image(_) => item.id.clone(), 206 | }) 207 | .collect(); 208 | 209 | trace!("(restore function) dedupe took {:?}", timer.elapsed()); 210 | } 211 | } 212 | 213 | debug!("restored {:?} clipboard items", self.hist.len()); 214 | 215 | trace!("restored clipboard in {:?}", timer.elapsed()); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/communication/mod.rs: -------------------------------------------------------------------------------- 1 | use interprocess::local_socket::{LocalSocketListener, LocalSocketStream, NameTypeSupport}; 2 | use std::io::{self, prelude::*, BufReader}; 3 | use tracing::{debug, warn}; 4 | 5 | use crate::{clipboard, menu}; 6 | 7 | pub struct SocketHandler { 8 | buffer: String, 9 | socket: SocketType, 10 | } 11 | 12 | pub enum SocketType { 13 | Server(LocalSocketListener), 14 | Client(LocalSocketStream), 15 | } 16 | 17 | pub type MPSCMessage = (String, usize); 18 | 19 | impl SocketHandler { 20 | pub fn server() -> Self { 21 | let name = get_socket_name(); 22 | 23 | let socket = match LocalSocketListener::bind(name) { 24 | Err(e) if e.kind() == io::ErrorKind::AddrInUse => { 25 | eprintln!("socket already in use, please check that wayclip is not already running"); 26 | std::process::exit(1); 27 | } 28 | x => x.unwrap(), 29 | }; 30 | 31 | debug!("server socket opened at {}", name); 32 | 33 | Self { 34 | buffer: String::with_capacity(128), 35 | socket: SocketType::Server(socket), 36 | } 37 | } 38 | 39 | pub fn client() -> Self { 40 | let name = get_socket_name(); 41 | 42 | let socket = match LocalSocketStream::connect(name) { 43 | Err(e) if e.kind() == io::ErrorKind::NotFound => { 44 | eprintln!("wayclip server is not running, please start it first"); 45 | std::process::exit(1); 46 | } 47 | x => x.unwrap(), 48 | }; 49 | 50 | debug!("client socket opened at {}", name); 51 | 52 | Self { 53 | buffer: String::with_capacity(128), 54 | socket: SocketType::Client(socket), 55 | } 56 | } 57 | 58 | pub fn listen( 59 | &mut self, 60 | clipboard: clipboard::WrappedClipboard, 61 | menu_message_sender: std::sync::mpsc::Sender, 62 | ) { 63 | match &mut self.socket { 64 | SocketType::Server(listener) => { 65 | for conn in listener.incoming().filter_map(handle_error) { 66 | let mut conn = BufReader::new(conn); 67 | conn.read_line(&mut self.buffer).unwrap(); 68 | debug!("server got toggle from client pid: {}", self.buffer); 69 | 70 | let clipboard = clipboard.clone(); 71 | let menu_message_sender = menu_message_sender.clone(); 72 | std::thread::spawn(move || { 73 | let mut menu = menu::init(clipboard).expect("failed to initialize a menu backend"); 74 | let result = menu.show(); 75 | 76 | let data = match result { 77 | Ok(Some(data)) => data, 78 | Ok(None) => return, 79 | Err(_) => return, 80 | }; 81 | 82 | debug!("selected: \"{:?}\" from menu of index \"{:?}\"", data.0, data.1); 83 | menu_message_sender.send(data).unwrap(); 84 | }); 85 | 86 | self.buffer.clear(); 87 | } 88 | } 89 | SocketType::Client(_) => panic!("Client cannot listen"), 90 | } 91 | } 92 | 93 | pub fn toggle(&mut self) { 94 | match &mut self.socket { 95 | SocketType::Client(conn) => { 96 | let pid = std::process::id(); 97 | debug!("my (client) pid is {} and i am going to message the server", pid); 98 | 99 | conn.write_all(format!("{}", pid).as_bytes()).unwrap(); 100 | } 101 | SocketType::Server(_) => panic!("Server cannot toggle"), 102 | } 103 | } 104 | } 105 | 106 | fn get_socket_name() -> &'static str { 107 | use NameTypeSupport::*; 108 | match NameTypeSupport::query() { 109 | OnlyPaths => "/run/wayclip.sock", 110 | OnlyNamespaced | Both => "@wayclip.sock", 111 | } 112 | } 113 | 114 | fn handle_error(conn: io::Result) -> Option { 115 | match conn { 116 | Ok(c) => Some(c), 117 | Err(e) => { 118 | warn!("Incoming connection failed: {}", e); 119 | None 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/config/cli.rs: -------------------------------------------------------------------------------- 1 | use clap::{Parser, Subcommand}; 2 | 3 | #[derive(Parser)] 4 | #[command(author, version, about, long_about = None)] 5 | pub struct Cli { 6 | #[command(subcommand)] 7 | pub command: Option, 8 | } 9 | 10 | #[derive(Subcommand)] 11 | pub enum Commands { 12 | /// [DEFAULT]; starts the clipboard monitor 13 | Start, 14 | /// activates the clipboard menu dropdown (for use in a keybinding) 15 | Toggle, 16 | /// dumps the clipboard contents to stdout 17 | Dump, 18 | /// empties the clipboard 19 | Clear, 20 | /// install 21 | Install, 22 | } 23 | -------------------------------------------------------------------------------- /src/config/consts.rs: -------------------------------------------------------------------------------- 1 | pub const APP_NAME: &str = "wayclip"; 2 | pub const CONFIG_FILE: &str = "config.toml"; 3 | pub const SYSTEMD_FILE: &str = "wayclip.service"; 4 | 5 | // config constants 6 | // [general] 7 | pub const MAX_HISTORY: usize = 0; 8 | pub const MENU: &str = "bemenu"; 9 | pub const ALLOW_IMAGES: bool = true; 10 | 11 | // [data] 12 | pub const MIME: &str = "text/plain"; 13 | pub const DEDUPE: bool = true; 14 | 15 | // [encryption] 16 | pub const ENCRYPT: bool = true; 17 | 18 | // [bemenu] 19 | pub const FONT: &str = "monospace 12"; 20 | pub const TITLE: &str = "search >"; 21 | pub const LINES: u32 = 15; 22 | pub const GRAB_FOCUS: bool = true; 23 | pub const MONITOR: i32 = -1; 24 | -------------------------------------------------------------------------------- /src/config/data.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use super::{consts::*, file::FileHelper}; 4 | use figment::{ 5 | providers::{Format, Toml}, 6 | Figment, 7 | }; 8 | use serde::Deserialize; 9 | 10 | #[derive(Clone, Deserialize, Debug, Default)] 11 | pub struct Config { 12 | #[serde(default)] 13 | pub general: General, 14 | #[serde(default)] 15 | pub data: Data, 16 | #[serde(default)] 17 | pub encryption: Encryption, 18 | #[serde(default)] 19 | pub bemenu: BeMenuConfig, 20 | 21 | // private 22 | #[serde(skip)] 23 | figment: Figment, 24 | #[serde(skip)] 25 | helper: FileHelper, 26 | #[serde(skip)] 27 | path: PathBuf, 28 | } 29 | 30 | impl Config { 31 | pub fn load(helper: FileHelper) -> Self { 32 | let path = helper.init_config(); 33 | let figment = Figment::new().join(Toml::file(path.clone())); 34 | let config = figment.extract::(); 35 | 36 | let mut config = match config { 37 | Ok(config) => config, 38 | Err(_) => Config::default(), 39 | }; 40 | config.figment = figment; 41 | config.helper = helper; 42 | config.path = path; 43 | 44 | config 45 | } 46 | } 47 | 48 | #[derive(Clone, Deserialize, Debug)] 49 | #[serde(rename_all = "camelCase")] 50 | pub struct General { 51 | #[serde(default)] 52 | pub max_history: usize, 53 | #[serde(default)] 54 | pub menu: String, 55 | #[serde(default)] 56 | pub allow_images: bool, 57 | } 58 | 59 | impl Default for General { 60 | fn default() -> Self { 61 | General { 62 | max_history: MAX_HISTORY, 63 | menu: MENU.to_string(), 64 | allow_images: ALLOW_IMAGES, 65 | } 66 | } 67 | } 68 | 69 | #[derive(Clone, Deserialize, Debug)] 70 | pub struct Data { 71 | #[serde(default)] 72 | pub mime: String, 73 | #[serde(default)] 74 | pub dedupe: bool, 75 | } 76 | 77 | impl Default for Data { 78 | fn default() -> Self { 79 | Data { 80 | mime: MIME.to_string(), 81 | dedupe: DEDUPE, 82 | } 83 | } 84 | } 85 | 86 | #[derive(Clone, Deserialize, Debug)] 87 | pub struct Encryption { 88 | #[serde(default)] 89 | pub encrypt: bool, 90 | #[serde(default)] 91 | pub key: Option, 92 | } 93 | 94 | impl Default for Encryption { 95 | fn default() -> Self { 96 | Encryption { 97 | encrypt: ENCRYPT, 98 | key: None, 99 | } 100 | } 101 | } 102 | 103 | #[derive(Clone, Deserialize, Debug)] 104 | #[serde(rename_all = "camelCase")] 105 | pub struct BeMenuConfig { 106 | #[serde(default)] 107 | pub font: String, 108 | #[serde(default)] 109 | pub title: String, 110 | #[serde(default)] 111 | pub lines: u32, 112 | #[serde(default)] 113 | pub grab_focus: bool, 114 | #[serde(default)] 115 | pub monitor: i32, 116 | } 117 | 118 | impl Default for BeMenuConfig { 119 | fn default() -> Self { 120 | BeMenuConfig { 121 | font: FONT.to_string(), 122 | title: TITLE.to_string(), 123 | lines: LINES, 124 | grab_focus: GRAB_FOCUS, 125 | monitor: MONITOR, 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/config/error.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub enum Error { 3 | BMenu(String), 4 | NoMenu, 5 | } 6 | -------------------------------------------------------------------------------- /src/config/file.rs: -------------------------------------------------------------------------------- 1 | use cocoon::MiniCocoon; 2 | use std::{fmt, fs, path::PathBuf}; 3 | 4 | use crate::clipboard::Item; 5 | 6 | use super::{ 7 | consts::{APP_NAME, CONFIG_FILE, SYSTEMD_FILE}, 8 | data::Config, 9 | resources::Resource, 10 | }; 11 | 12 | pub fn generate_cocoon(seed: [u8; 32], key: Option) -> MiniCocoon { 13 | let key = match key { 14 | Some(key) => { 15 | if key.is_empty() { 16 | machine_uid::get().unwrap() 17 | } else { 18 | key 19 | } 20 | } 21 | None => machine_uid::get().unwrap(), 22 | }; 23 | 24 | MiniCocoon::from_password(key.as_bytes(), &seed) 25 | } 26 | 27 | #[derive(Default)] 28 | pub struct FileHelper { 29 | pub config_dir: PathBuf, 30 | pub cache_dir: PathBuf, 31 | pub log_dir: PathBuf, 32 | pub systemd_dir: PathBuf, 33 | 34 | // privates 35 | cocoon: Option, 36 | } 37 | 38 | impl Clone for FileHelper { 39 | fn clone(&self) -> Self { 40 | FileHelper { 41 | config_dir: self.config_dir.clone(), 42 | cache_dir: self.cache_dir.clone(), 43 | log_dir: self.log_dir.clone(), 44 | systemd_dir: self.systemd_dir.clone(), 45 | 46 | // privates 47 | cocoon: None, 48 | } 49 | } 50 | } 51 | 52 | impl fmt::Debug for FileHelper { 53 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 54 | f.debug_struct("FileHelper") 55 | .field("config_dir", &self.config_dir) 56 | .field("cache_dir", &self.cache_dir) 57 | .field("log_dir", &self.log_dir) 58 | .finish() 59 | } 60 | } 61 | 62 | impl FileHelper { 63 | pub fn new() -> Self { 64 | let config_dir = init_dir(dirs::config_dir().unwrap().join(APP_NAME)); 65 | let cache_dir = init_dir(dirs::cache_dir().unwrap().join(APP_NAME)); 66 | let log_dir = init_dir(dirs::data_dir().unwrap().join(APP_NAME)); 67 | let systemd_dir = init_dir(dirs::config_dir().unwrap().join("systemd/user")); 68 | 69 | FileHelper { 70 | config_dir, 71 | cache_dir, 72 | log_dir, 73 | systemd_dir, 74 | 75 | // privates 76 | cocoon: None, 77 | } 78 | } 79 | 80 | pub fn init_config(&self) -> PathBuf { 81 | if !self.config_dir.join(CONFIG_FILE).exists() { 82 | let default = Resource::get(CONFIG_FILE).unwrap(); 83 | fs::write(self.config_dir.join(CONFIG_FILE), default.data).unwrap(); 84 | } 85 | 86 | self.config_dir.join(CONFIG_FILE) 87 | } 88 | 89 | pub fn install_systemd_file(&self) -> PathBuf { 90 | let file = self.systemd_dir.join(SYSTEMD_FILE); 91 | 92 | if !file.exists() { 93 | let default = Resource::get(SYSTEMD_FILE).unwrap(); 94 | fs::write(file.clone(), default.data).unwrap(); 95 | } 96 | 97 | file 98 | } 99 | 100 | pub fn persist_clipboard(&self, clipboard: Vec) { 101 | let encoded = bincode::serialize(&clipboard).unwrap(); 102 | let cocoon = self.cocoon.as_ref().unwrap(); 103 | 104 | let mut writer = self.get_clipboard_file(); 105 | cocoon.dump(encoded, &mut writer).unwrap(); 106 | } 107 | 108 | pub fn retrieve_clipboard(&self) -> Option> { 109 | if !self.cache_dir.join("clipboard.bin").is_file() { 110 | return None; 111 | } 112 | 113 | let mut reader = self.get_clipboard_file(); 114 | let cocoon = self.cocoon.as_ref().unwrap(); 115 | 116 | let decrypted = cocoon.parse(&mut reader).unwrap(); 117 | bincode::deserialize::>(&decrypted).ok() 118 | } 119 | 120 | pub fn init_cocoon(&mut self, config: &Config) { 121 | let seed = self.get_seed(); 122 | let cocoon = generate_cocoon(seed, config.encryption.key.clone()); 123 | 124 | self.cocoon = Some(cocoon); 125 | } 126 | 127 | fn get_clipboard_file(&self) -> fs::File { 128 | let path = self.cache_dir.join("clipboard.bin"); 129 | 130 | if path.is_file() { 131 | return fs::OpenOptions::new().read(true).write(true).open(path).unwrap(); 132 | } 133 | 134 | fs::File::create(path).unwrap() 135 | } 136 | 137 | fn get_seed_file(&self) -> fs::File { 138 | let path = self.config_dir.join("seed.bin"); 139 | 140 | if path.is_file() { 141 | return fs::OpenOptions::new().read(true).write(true).open(path).unwrap(); 142 | } 143 | 144 | fs::File::create(path).unwrap() 145 | } 146 | 147 | fn get_seed(&self) -> [u8; 32] { 148 | use std::io::{Read, Write}; 149 | 150 | let mut handle = self.get_seed_file(); 151 | let mut seed = [0u8; 32]; 152 | 153 | let success = handle.read_exact(&mut seed); 154 | 155 | if success.is_err() { 156 | use rand::Rng; 157 | seed = rand::thread_rng().gen::<[u8; 32]>(); 158 | 159 | handle.write_all(&seed).unwrap(); 160 | } 161 | 162 | seed 163 | } 164 | } 165 | 166 | fn init_dir(dir: PathBuf) -> PathBuf { 167 | if dir.is_dir() { 168 | return dir; 169 | } 170 | 171 | fs::create_dir_all(dir.as_path()).unwrap(); 172 | 173 | dir 174 | } 175 | -------------------------------------------------------------------------------- /src/config/install.rs: -------------------------------------------------------------------------------- 1 | use crate::config::consts::SYSTEMD_FILE; 2 | 3 | use super::file::FileHelper; 4 | 5 | pub fn install(helper: FileHelper) { 6 | let path = helper.install_systemd_file(); 7 | 8 | println!("Installed systemd file to: {}", path.display()); 9 | print!("Would you like to enable it now? [y/N]: "); 10 | 11 | use std::io::Write; 12 | std::io::stdout().flush().unwrap(); 13 | 14 | let mut input = String::new(); 15 | std::io::stdin().read_line(&mut input).unwrap(); 16 | 17 | if input.trim().to_lowercase() == "y" { 18 | std::process::Command::new("systemctl") 19 | .arg("--user") 20 | .arg("enable") 21 | .arg(SYSTEMD_FILE) 22 | .arg("--now") 23 | .spawn() 24 | .unwrap(); 25 | println!("\nEnabling and starting {}", SYSTEMD_FILE); 26 | } else { 27 | println!( 28 | "\nYou can enable it later by running: systemctl --user enable {}", 29 | SYSTEMD_FILE 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/config/mod.rs: -------------------------------------------------------------------------------- 1 | use self::{data::Config, file::FileHelper}; 2 | 3 | pub mod cli; 4 | mod consts; 5 | pub mod data; 6 | pub mod error; 7 | pub mod file; 8 | pub mod install; 9 | mod resources; 10 | 11 | pub fn init(mut helper: FileHelper) -> (Config, FileHelper) { 12 | let config = Config::load(helper.clone()); 13 | helper.init_cocoon(&config); 14 | 15 | (config, helper) 16 | } 17 | 18 | pub fn init_helper() -> FileHelper { 19 | FileHelper::new() 20 | } 21 | -------------------------------------------------------------------------------- /src/config/resources.rs: -------------------------------------------------------------------------------- 1 | use rust_embed::RustEmbed; 2 | 3 | #[derive(RustEmbed)] 4 | #[folder = "resources/"] 5 | pub struct Resource; 6 | -------------------------------------------------------------------------------- /src/input/mod.rs: -------------------------------------------------------------------------------- 1 | use evdev::{ 2 | uinput::{VirtualDevice, VirtualDeviceBuilder}, 3 | AttributeSet, EventType, InputEvent, Key, 4 | }; 5 | 6 | pub struct UDevice { 7 | device: VirtualDevice, 8 | } 9 | 10 | impl UDevice { 11 | pub fn new() -> Self { 12 | let mut keys = AttributeSet::::new(); 13 | keys.insert(Key::KEY_PASTE); 14 | 15 | let device = VirtualDeviceBuilder::new() 16 | .unwrap() 17 | .name("wayclip") 18 | .with_keys(&keys) 19 | .unwrap() 20 | .build() 21 | .unwrap(); 22 | 23 | Self { device } 24 | } 25 | 26 | pub fn paste(&mut self) { 27 | let type_ = EventType::KEY; 28 | let code = Key::KEY_PASTE.code(); 29 | 30 | let down_event = InputEvent::new(type_, code, 1); 31 | self.device.emit(&[down_event]).unwrap(); 32 | let up_event = InputEvent::new(type_, code, 0); 33 | self.device.emit(&[up_event]).unwrap(); 34 | } 35 | 36 | pub fn copy(&self, text: String, mime: String) { 37 | let opts = wl_clipboard_rs::copy::Options::new(); 38 | opts 39 | .copy( 40 | wl_clipboard_rs::copy::Source::Bytes(text.into_bytes().into()), 41 | wl_clipboard_rs::copy::MimeType::Specific(mime), 42 | ) 43 | .unwrap(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(let_chains)] 2 | #![feature(if_let_guard)] 3 | 4 | use clap::Parser; 5 | 6 | mod clipboard; 7 | mod communication; 8 | mod config; 9 | mod input; 10 | mod menu; 11 | mod wayland; 12 | 13 | fn main() { 14 | let helper = config::init_helper(); 15 | let _guard = init_logger(helper.log_dir.clone()); 16 | 17 | let cli = config::cli::Cli::parse(); 18 | 19 | match &cli.command { 20 | Some(config::cli::Commands::Toggle) => toggle(), 21 | Some(config::cli::Commands::Install) => config::install::install(helper), 22 | Some(config::cli::Commands::Dump) => dump(helper), 23 | Some(config::cli::Commands::Clear) => clear(helper), 24 | _ => run(helper), 25 | } 26 | } 27 | 28 | fn run(helper: config::file::FileHelper) { 29 | let (config, helper) = config::init(helper); 30 | 31 | // bemenu -> wayland 32 | let (tx, rx) = std::sync::mpsc::channel::(); 33 | 34 | let clipboard = clipboard::Clipboard::init(config, helper); 35 | let t_clipboard = clipboard.clone(); 36 | 37 | std::thread::spawn(move || { 38 | communication::SocketHandler::server().listen(clipboard, tx); 39 | }); 40 | 41 | wayland::watch_clipboard(t_clipboard, rx); 42 | } 43 | 44 | fn toggle() { 45 | communication::SocketHandler::client().toggle(); 46 | } 47 | 48 | fn dump(helper: config::file::FileHelper) { 49 | let (config, helper) = config::init(helper); 50 | 51 | let clipboard = clipboard::Clipboard::init(config, helper); 52 | clipboard.read().unwrap().dump(); 53 | } 54 | 55 | fn clear(helper: config::file::FileHelper) { 56 | let (config, helper) = config::init(helper); 57 | 58 | let clipboard = clipboard::Clipboard::init(config, helper); 59 | clipboard.write().unwrap().clear(); 60 | } 61 | 62 | fn init_logger(log_dir: std::path::PathBuf) -> tracing_appender::non_blocking::WorkerGuard { 63 | use tracing::metadata::LevelFilter; 64 | use tracing_subscriber::{ 65 | filter::Directive, fmt, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer, 66 | }; 67 | 68 | #[cfg(debug_assertions)] 69 | let file_appender = tracing_appender::rolling::daily(log_dir, "wayclip-debug.log"); 70 | #[cfg(not(debug_assertions))] 71 | let file_appender = tracing_appender::rolling::daily(log_dir, "wayclip.log"); 72 | 73 | let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); 74 | 75 | // directives for debug builds 76 | #[cfg(debug_assertions)] 77 | let default_directive = Directive::from(LevelFilter::TRACE); 78 | 79 | #[cfg(debug_assertions)] 80 | let filter_directives = if let Ok(filter) = std::env::var("RUST_LOG") { 81 | filter 82 | } else { 83 | "wayclip=trace".to_string() 84 | }; 85 | 86 | // directives for release builds 87 | #[cfg(not(debug_assertions))] 88 | let default_directive = Directive::from(LevelFilter::INFO); 89 | 90 | #[cfg(not(debug_assertions))] 91 | let filter_directives = if let Ok(filter) = std::env::var("RUST_LOG") { 92 | filter 93 | } else { 94 | "wayclip=info".to_string() 95 | }; 96 | 97 | let filter = EnvFilter::builder() 98 | .with_default_directive(default_directive) 99 | .parse_lossy(filter_directives); 100 | 101 | tracing_subscriber::registry() 102 | .with(fmt::layer().with_writer(non_blocking).with_filter(filter)) 103 | .init(); 104 | 105 | guard 106 | } 107 | -------------------------------------------------------------------------------- /src/menu/bemenu.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | #![allow(dead_code)] 5 | 6 | use crate::{clipboard, config::error::Error}; 7 | use std::ffi::CString; 8 | 9 | use super::Menu; 10 | 11 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 12 | 13 | pub struct BeMenu { 14 | clipboard: clipboard::WrappedClipboard, 15 | 16 | menu: *mut bm_menu, 17 | items: Vec<(*mut bm_item, *mut usize)>, 18 | } 19 | 20 | impl Menu for BeMenu { 21 | fn new(clipboard: clipboard::WrappedClipboard) -> Result, Error> { 22 | if !unsafe { bm_init() } { 23 | return Err(Error::BMenu("Failed to initialize bmenu".into())); 24 | }; 25 | 26 | Ok(Box::new(Self { 27 | clipboard, 28 | 29 | menu: unsafe { bm_menu_new(std::ptr::null()) }, 30 | items: Vec::new(), 31 | })) 32 | } 33 | 34 | fn show(&mut self) -> Result, Error> { 35 | let menu = self.menu; 36 | self.handle_config(menu); 37 | self.add_items(menu); 38 | 39 | unsafe { 40 | let unicode: *mut u32 = &mut 0; 41 | let mut status: bm_run_result; 42 | 43 | loop { 44 | bm_menu_render(menu); 45 | let key = bm_menu_poll_key(menu, unicode); 46 | let pointer = bm_menu_poll_pointer(menu); 47 | let touch = bm_menu_poll_touch(menu); 48 | 49 | status = bm_menu_run_with_events(menu, key, pointer, touch, *unicode); 50 | if status != bm_run_result_BM_RUN_RESULT_RUNNING { 51 | break; 52 | } 53 | } 54 | 55 | if status == bm_run_result_BM_RUN_RESULT_SELECTED { 56 | let selected = *bm_menu_get_selected_items(menu, std::ptr::null_mut()); 57 | let selected_idx = bm_item_get_userdata(selected) as *mut i32; 58 | let text = std::ffi::CStr::from_ptr(bm_item_get_text(selected)).to_str().unwrap(); 59 | 60 | return Ok(Some((text.to_string(), *Box::from_raw(selected_idx) as usize))); 61 | } else if status == bm_run_result_BM_RUN_RESULT_CANCEL { 62 | return Ok(None); 63 | } 64 | }; 65 | 66 | Ok(None) 67 | } 68 | } 69 | 70 | impl BeMenu { 71 | fn handle_config(&self, menu: *mut bm_menu) { 72 | let cb = self.clipboard.clone(); 73 | let config = cb.read().unwrap().get_config().bemenu; 74 | 75 | unsafe { 76 | bm_menu_set_filter_mode(menu, bm_filter_mode_BM_FILTER_MODE_DMENU_CASE_INSENSITIVE); 77 | bm_menu_set_lines(menu, config.lines); 78 | bm_menu_set_title(menu, std::ffi::CStr::as_ptr(&CString::new(config.title).unwrap())); 79 | bm_menu_set_font(menu, std::ffi::CStr::as_ptr(&CString::new(config.font).unwrap())); 80 | bm_menu_grab_keyboard(menu, config.grab_focus); 81 | bm_menu_set_monitor(menu, config.monitor); 82 | bm_menu_set_spacing(menu, true); 83 | } 84 | } 85 | 86 | fn add_items(&mut self, menu: *mut bm_menu) { 87 | for (idx, item) in (self.clipboard.read().unwrap().hist).iter().rev().enumerate() { 88 | match &item.data { 89 | clipboard::ItemData::Text(data) => unsafe { 90 | let (item, idx) = self.create_text_item(data, idx); 91 | bm_menu_add_item(menu, item); 92 | self.items.push((item, idx)); 93 | }, 94 | clipboard::ItemData::Image(_) => {} 95 | } 96 | } 97 | } 98 | 99 | fn create_text_item(&self, item: &clipboard::TextItem, idx: usize) -> (*mut bm_item, *mut usize) { 100 | let item = CString::new(item.text.clone()).unwrap(); 101 | unsafe { 102 | let item = bm_item_new(std::ffi::CStr::as_ptr(&item)); 103 | let idx = Box::into_raw(Box::new(idx)); 104 | 105 | bm_item_set_userdata(item, idx as *mut _); 106 | 107 | (item, idx) 108 | } 109 | } 110 | } 111 | 112 | impl Drop for BeMenu { 113 | fn drop(&mut self) { 114 | unsafe { 115 | bm_menu_free(self.menu); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/menu/mod.rs: -------------------------------------------------------------------------------- 1 | mod bemenu; 2 | 3 | use crate::{clipboard, config::error::Error}; 4 | 5 | pub trait Menu { 6 | fn new(clipboard: clipboard::WrappedClipboard) -> Result, Error> 7 | where 8 | Self: Sized; 9 | fn show(&mut self) -> Result, Error>; 10 | } 11 | 12 | pub type WrappedMenu = Box; 13 | 14 | pub fn init(clipboard: clipboard::WrappedClipboard) -> Result { 15 | if let Ok(menu) = bemenu::BeMenu::new(clipboard) { 16 | Ok(menu) 17 | } else { 18 | Err(Error::NoMenu) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/wayland/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | io::Read, 3 | os::{fd::BorrowedFd, unix::io::AsRawFd}, 4 | }; 5 | 6 | use tracing::{debug, trace}; 7 | use wayland_client::{ 8 | event_created_child, 9 | protocol::{ 10 | wl_registry, 11 | wl_seat::{self, WlSeat}, 12 | }, 13 | Connection, Dispatch, EventQueue, Proxy, QueueHandle, 14 | }; 15 | 16 | use wayland_protocols_wlr::data_control::v1::client::{ 17 | zwlr_data_control_device_v1::{self, ZwlrDataControlDeviceV1}, 18 | zwlr_data_control_manager_v1::ZwlrDataControlManagerV1, 19 | zwlr_data_control_offer_v1::{self, ZwlrDataControlOfferV1}, 20 | }; 21 | 22 | use crate::{ 23 | clipboard::{self, WrappedClipboard}, 24 | communication, input, 25 | }; 26 | 27 | #[derive(Clone, Debug)] 28 | struct WaylandState { 29 | clipboard: WrappedClipboard, 30 | 31 | seat: Option, 32 | manager: Option, 33 | device: Option, 34 | } 35 | 36 | impl Dispatch for WaylandState { 37 | fn event( 38 | state: &mut Self, 39 | registry: &wl_registry::WlRegistry, 40 | event: wl_registry::Event, 41 | _: &(), 42 | _: &Connection, 43 | qh: &QueueHandle, 44 | ) { 45 | if let wl_registry::Event::Global { 46 | name, 47 | interface, 48 | version: _version, 49 | } = event 50 | { 51 | // println!("[{}] {} (v{})", name, interface, _version); 52 | match &interface[..] { 53 | "wl_seat" => { 54 | registry.bind::(name, 1, qh, ()); 55 | } 56 | "zwlr_data_control_manager_v1" => { 57 | state.manager = Some(registry.bind::(name, 1, qh, ())); 58 | } 59 | _ => {} 60 | } 61 | } 62 | } 63 | } 64 | 65 | impl Dispatch for WaylandState { 66 | fn event(state: &mut Self, seat: &wl_seat::WlSeat, _: wl_seat::Event, _: &(), _: &Connection, _: &QueueHandle) { 67 | if state.seat.is_some() { 68 | return; 69 | }; 70 | 71 | state.seat = Some(seat.clone()); 72 | } 73 | } 74 | 75 | impl Dispatch for WaylandState { 76 | fn event( 77 | _: &mut Self, 78 | _: &ZwlrDataControlManagerV1, 79 | _: ::Event, 80 | _: &(), 81 | _: &Connection, 82 | _: &QueueHandle, 83 | ) { 84 | } 85 | } 86 | 87 | // impl Dispatch for WaylandState { 88 | // fn event( 89 | // _: &mut Self, 90 | // _: &ZwlrDataControlSourceV1, 91 | // _: ::Event, 92 | // _: &(), 93 | // _: &Connection, 94 | // _: &QueueHandle, 95 | // ) { 96 | // panic!("source event"); 97 | // } 98 | // } 99 | 100 | impl Dispatch for WaylandState { 101 | fn event( 102 | state: &mut Self, 103 | _: &ZwlrDataControlDeviceV1, 104 | event: ::Event, 105 | _: &(), 106 | conn: &Connection, 107 | _: &QueueHandle, 108 | ) { 109 | match event { 110 | zwlr_data_control_device_v1::Event::DataOffer { id } => { 111 | let id = id.id(); 112 | trace!("data offer id: {:?}", id); 113 | state.clipboard.write().unwrap().new_offer(id); 114 | } 115 | 116 | zwlr_data_control_device_v1::Event::Selection { id } if id.is_some() => { 117 | let id = id.unwrap().id(); 118 | trace!("selection id: {:?}", id); 119 | let item = get_item(conn, state); 120 | if let Some(item) = item { 121 | state.clipboard.write().unwrap().commit(item); 122 | } 123 | } 124 | _ => {} 125 | } 126 | } 127 | 128 | event_created_child!( 129 | WaylandState, 130 | ZwlrDataControlDeviceV1, 131 | [zwlr_data_control_device_v1::EVT_DATA_OFFER_OPCODE => (ZwlrDataControlOfferV1, ())] 132 | ); 133 | } 134 | 135 | fn get_item(conn: &Connection, state: &WaylandState) -> Option { 136 | let borrow = state.clipboard.read().unwrap(); 137 | let live = if let Some(live) = &borrow.live { 138 | live 139 | } else { 140 | return None; 141 | }; 142 | 143 | let offer = live.offer.as_ref().unwrap(); 144 | 145 | if let Some(mime_type) = live.mime_types.iter().find(|mime_type| mime_type.starts_with("image/")) { 146 | debug!("image mime type found: {:?}", mime_type); 147 | 148 | if !state.clipboard.read().unwrap().get_config().general.allow_images { 149 | return None; 150 | } 151 | 152 | let (mut read, write) = os_pipe::pipe().expect("fuck shit"); 153 | offer.receive((*mime_type).clone(), unsafe { 154 | BorrowedFd::borrow_raw(write.as_raw_fd()) 155 | }); 156 | drop(write); 157 | 158 | conn.roundtrip().unwrap(); 159 | 160 | let mut buffer = vec![]; 161 | read.read_to_end(&mut buffer).unwrap(); 162 | 163 | debug!("image buffer size: {:?} bytes", buffer.len()); 164 | 165 | trace!("wayland data transferred in: {:?}", live.instant.elapsed()); 166 | 167 | if let Some(file_type) = infer::get(&buffer) { 168 | debug!("file type: {:?} confirmed", file_type); 169 | let item = clipboard::Item { 170 | id: live.id.to_string(), 171 | data: clipboard::ItemData::Image(clipboard::ImageItem { 172 | image: buffer, 173 | mime: mime_type.to_string(), 174 | }), 175 | }; 176 | 177 | return Some(item); 178 | } 179 | } 180 | 181 | let preferred_text_mime = state.clipboard.read().unwrap().preferred_text_mime(); 182 | let (mut read, write) = os_pipe::pipe().expect("fuck shit"); 183 | 184 | offer.receive(preferred_text_mime.clone(), unsafe { 185 | BorrowedFd::borrow_raw(write.as_raw_fd()) 186 | }); 187 | drop(write); 188 | 189 | conn.roundtrip().unwrap(); 190 | 191 | let mut text = String::new(); 192 | read.read_to_string(&mut text).unwrap(); 193 | 194 | debug!("text buffer size: {:?} bytes", text.clone().as_bytes().len()); 195 | 196 | trace!("wayland data transferred in: {:?}", live.instant.elapsed()); 197 | 198 | if text.trim().is_empty() { 199 | return None; 200 | } 201 | 202 | let item = clipboard::Item { 203 | id: live.id.to_string(), 204 | data: clipboard::ItemData::Text(clipboard::TextItem { 205 | text, 206 | mime: preferred_text_mime, 207 | }), 208 | }; 209 | 210 | Some(item) 211 | } 212 | 213 | impl Dispatch for WaylandState { 214 | fn event( 215 | state: &mut Self, 216 | offer: &ZwlrDataControlOfferV1, 217 | event: ::Event, 218 | _: &(), 219 | _: &Connection, 220 | _: &QueueHandle, 221 | ) { 222 | // println!("offer: {:?}", offer); 223 | let mut borrow = state.clipboard.write().unwrap(); 224 | let live = if let Some(live) = &mut borrow.live { 225 | live 226 | } else { 227 | debug!("no in progress"); 228 | return; 229 | }; 230 | 231 | let mime_type = match event { 232 | zwlr_data_control_offer_v1::Event::Offer { mime_type } => mime_type, 233 | _ => return, 234 | }; 235 | 236 | live.handle_offer(offer, mime_type); 237 | } 238 | } 239 | 240 | impl WaylandState { 241 | fn new(clipboard: WrappedClipboard) -> (Self, EventQueue) { 242 | let conn = Connection::connect_to_env().unwrap(); 243 | 244 | let display = conn.display(); 245 | let mut queue = conn.new_event_queue(); 246 | let qh: QueueHandle = queue.handle(); 247 | 248 | let _registry = display.get_registry(&qh, ()); 249 | 250 | let mut state = WaylandState { 251 | clipboard, 252 | 253 | seat: None, 254 | manager: None, 255 | device: None, 256 | }; 257 | 258 | // double roundtrip needed for seat to be set 259 | queue.roundtrip(&mut state).unwrap(); 260 | queue.roundtrip(&mut state).unwrap(); 261 | 262 | let seat = state.seat.clone().unwrap(); 263 | state.device = Some(state.manager.as_ref().unwrap().get_data_device(&seat, &qh, ())); 264 | 265 | (state, queue) 266 | } 267 | } 268 | 269 | pub fn watch_clipboard( 270 | clipboard: WrappedClipboard, 271 | menu_message_receiver: std::sync::mpsc::Receiver, 272 | ) { 273 | let (mut state, mut queue) = WaylandState::new(clipboard.clone()); 274 | let mut dev = input::UDevice::new(); 275 | 276 | std::thread::spawn(move || loop { 277 | let (message, index) = menu_message_receiver.recv().unwrap(); 278 | dev.copy(message, clipboard.read().unwrap().get_config().data.mime.clone()); 279 | dev.paste(); 280 | 281 | clipboard.write().unwrap().pasted_idx(index); 282 | }); 283 | 284 | loop { 285 | queue.blocking_dispatch(&mut state).unwrap(); 286 | } 287 | } 288 | --------------------------------------------------------------------------------