From e2a0fb204724c5b6fc12554a35355a6a419ad198 Mon Sep 17 00:00:00 2001 From: Alexandre Pasmantier <47638216+alexpasmantier@users.noreply.github.com> Date: Mon, 24 Feb 2025 21:50:53 +0100 Subject: [PATCH] fix(clipboard): fix issue where clipboard wouldn't work on X11-based environments (#364) fixes #282 tested with the following setup: ``` -` alex@alex-mbp .o+` ------------- `ooo/ OS: Arch Linux x86_64 `+oooo: Host: MacBookPro10,2 1.0 `+oooooo: Kernel: 6.13.3-arch1-1 -+oooooo+: Uptime: 1 hour, 8 mins `/:-:++oooo+: Packages: 559 (pacman) `/++++/+++++++: Shell: zsh 5.9 `/++++++++++++++: Resolution: 2048x1280 `/+++ooooooooooooo/` WM: awesome ./ooosssso++osssssso+` Theme: Adwaita [GTK3] .oossssso-````/ossssss+` Icons: Adwaita [GTK3] -osssssso. :ssssssso. Terminal: tmux :osssssss/ osssso+++. CPU: Intel i5-3230M (4) @ 3.200GHz /ossssssss/ +ssssooo/- GPU: Intel 3rd Gen Core processor Graphics Controller `/ossssso+/:- -:/+osssso+- Memory: 4180MiB / 7815MiB `+sso+:-` `.-/+oso: `++:. `-/+/ .` `/ ``` --- Cargo.lock | 464 ++-------------------------------- Cargo.toml | 3 +- television/main.rs | 3 + television/television.rs | 24 +- television/utils/clipboard.rs | 177 +++++++++++++ television/utils/mod.rs | 2 + television/utils/rocell.rs | 99 ++++++++ 7 files changed, 318 insertions(+), 454 deletions(-) create mode 100644 television/utils/clipboard.rs create mode 100644 television/utils/rocell.rs diff --git a/Cargo.lock b/Cargo.lock index fdab5f6..4d6b777 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,7 +121,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -201,12 +201,6 @@ dependencies = [ "serde", ] -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - [[package]] name = "bstr" version = "1.11.3" @@ -241,32 +235,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" -[[package]] -name = "calloop" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" -dependencies = [ - "bitflags 2.8.0", - "log", - "polling", - "rustix", - "slab", - "thiserror 1.0.69", -] - -[[package]] -name = "calloop-wayland-source" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" -dependencies = [ - "calloop", - "rustix", - "wayland-backend", - "wayland-client", -] - [[package]] name = "cassowary" version = "0.3.0" @@ -372,12 +340,11 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "clipboard-win" -version = "3.1.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" dependencies = [ - "lazy-bytes-cast", - "winapi", + "error-code", ] [[package]] @@ -411,15 +378,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "console" version = "0.15.10" @@ -442,20 +400,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "copypasta" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb85422867ca93da58b7f95fb5c0c10f6183ed6e1ef8841568968a896d3a858" -dependencies = [ - "clipboard-win", - "objc", - "objc-foundation", - "objc_id", - "smithay-clipboard", - "x11-clipboard", -] - [[package]] name = "crc32fast" version = "1.4.2" @@ -561,12 +505,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" -[[package]] -name = "cursor-icon" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" - [[package]] name = "darling" version = "0.20.10" @@ -641,21 +579,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading", -] - -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - [[package]] name = "either" version = "1.13.0" @@ -693,6 +616,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "error-code" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" + [[package]] name = "fastrand" version = "2.3.0" @@ -803,16 +732,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "gethostname" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" -dependencies = [ - "libc", - "windows-targets 0.48.5", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -833,7 +752,7 @@ dependencies = [ "cfg-if", "libc", "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1016,12 +935,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "lazy-bytes-cast" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b" - [[package]] name = "lazy_static" version = "1.5.0" @@ -1034,16 +947,6 @@ version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" -[[package]] -name = "libloading" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" -dependencies = [ - "cfg-if", - "windows-targets 0.52.6", -] - [[package]] name = "libredox" version = "0.1.3" @@ -1085,15 +988,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - [[package]] name = "matchers" version = "0.1.0" @@ -1109,15 +1003,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memmap2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" -dependencies = [ - "libc", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1210,35 +1095,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] - -[[package]] -name = "objc_id" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" -dependencies = [ - "objc", -] - [[package]] name = "object" version = "0.36.7" @@ -1325,7 +1181,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1369,7 +1225,7 @@ checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64", "indexmap", - "quick-xml 0.32.0", + "quick-xml", "serde", "time", ] @@ -1402,21 +1258,6 @@ dependencies = [ "plotters-backend", ] -[[package]] -name = "polling" -version = "3.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix", - "tracing", - "windows-sys 0.59.0", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -1441,15 +1282,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "quick-xml" -version = "0.37.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003" -dependencies = [ - "memchr", -] - [[package]] name = "quote" version = "1.0.38" @@ -1620,12 +1452,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -1766,57 +1592,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "smithay-client-toolkit" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" -dependencies = [ - "bitflags 2.8.0", - "calloop", - "calloop-wayland-source", - "cursor-icon", - "libc", - "log", - "memmap2", - "rustix", - "thiserror 1.0.69", - "wayland-backend", - "wayland-client", - "wayland-csd-frame", - "wayland-cursor", - "wayland-protocols", - "wayland-protocols-wlr", - "wayland-scanner", - "xkeysym", -] - -[[package]] -name = "smithay-clipboard" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8216eec463674a0e90f29e0ae41a4db573ec5b56b1c6c1c71615d249b6d846" -dependencies = [ - "libc", - "smithay-client-toolkit", - "wayland-backend", -] - [[package]] name = "socket2" version = "0.5.8" @@ -1903,10 +1684,11 @@ name = "television" version = "0.10.6" dependencies = [ "anyhow", + "base64", "bat", "better-panic", "clap", - "copypasta", + "clipboard-win", "criterion", "crossterm", "devicons", @@ -2348,102 +2130,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wayland-backend" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" -dependencies = [ - "cc", - "downcast-rs", - "rustix", - "scoped-tls", - "smallvec", - "wayland-sys", -] - -[[package]] -name = "wayland-client" -version = "0.31.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" -dependencies = [ - "bitflags 2.8.0", - "rustix", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-csd-frame" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" -dependencies = [ - "bitflags 2.8.0", - "cursor-icon", - "wayland-backend", -] - -[[package]] -name = "wayland-cursor" -version = "0.31.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" -dependencies = [ - "rustix", - "wayland-client", - "xcursor", -] - -[[package]] -name = "wayland-protocols" -version = "0.32.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" -dependencies = [ - "bitflags 2.8.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols-wlr" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2" -dependencies = [ - "bitflags 2.8.0", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" -dependencies = [ - "proc-macro2", - "quick-xml 0.37.2", - "quote", -] - -[[package]] -name = "wayland-sys" -version = "0.31.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" -dependencies = [ - "dlib", - "log", - "once_cell", - "pkg-config", -] - [[package]] name = "web-sys" version = "0.3.77" @@ -2492,7 +2178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" dependencies = [ "windows-core", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2504,7 +2190,7 @@ dependencies = [ "windows-implement", "windows-interface", "windows-result", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2535,7 +2221,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2544,7 +2230,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2553,22 +2239,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -2577,46 +2248,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -2629,48 +2282,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -2695,45 +2324,6 @@ dependencies = [ "bitflags 2.8.0", ] -[[package]] -name = "x11-clipboard" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662d74b3d77e396b8e5beb00b9cad6a9eccf40b2ef68cc858784b14c41d535a3" -dependencies = [ - "libc", - "x11rb", -] - -[[package]] -name = "x11rb" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" -dependencies = [ - "gethostname", - "rustix", - "x11rb-protocol", -] - -[[package]] -name = "x11rb-protocol" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" - -[[package]] -name = "xcursor" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" - -[[package]] -name = "xkeysym" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" - [[package]] name = "xterm-color" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 4f46516..c31c645 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ path = "television/lib.rs" television-derive = { path = "television-derive", version = "0.0.25" } anyhow = "1.0" +base64 = "0.22.1" directories = "6.0" devicons = "0.6" lazy_static = "1.5" @@ -46,7 +47,6 @@ ratatui = { version = "0.29", features = ["serde", "macros"] } better-panic = "0.3" signal-hook = "0.3" human-panic = "2.0" -copypasta = "0.10" ignore = "0.4" strum = { version = "0.26", features = ["derive"] } regex = "1.11" @@ -62,6 +62,7 @@ toml = "0.8" [target.'cfg(windows)'.dependencies] winapi-util = "0.1.9" +clipboard-win = "5.4.0" [dev-dependencies] criterion = { version = "0.5", features = ["async_tokio"] } diff --git a/television/main.rs b/television/main.rs index 9eed959..d60b447 100644 --- a/television/main.rs +++ b/television/main.rs @@ -5,6 +5,7 @@ use std::process::exit; use anyhow::Result; use clap::Parser; +use television::utils::clipboard::CLIPBOARD; use tracing::{debug, error, info}; use television::app::App; @@ -77,6 +78,8 @@ async fn main() -> Result<()> { env::set_current_dir(path)?; } + CLIPBOARD.with(<_>::default); + match App::new( { if is_readable_stdin() { diff --git a/television/television.rs b/television/television.rs index c5acc44..980d33b 100644 --- a/television/television.rs +++ b/television/television.rs @@ -13,15 +13,14 @@ use crate::preview::{PreviewState, Previewer}; use crate::screen::colors::Colorscheme; use crate::screen::layout::InputPosition; use crate::screen::spinner::{Spinner, SpinnerState}; +use crate::utils::clipboard::CLIPBOARD; use crate::utils::metadata::AppMetadata; use crate::utils::strings::EMPTY_STRING; use anyhow::Result; -use copypasta::{ClipboardContext, ClipboardProvider}; use rustc_hash::{FxBuildHasher, FxHashSet}; use serde::{Deserialize, Serialize}; use std::collections::HashSet; use tokio::sync::mpsc::{Receiver, Sender, UnboundedSender}; -use tracing::error; #[derive(PartialEq, Copy, Clone, Hash, Eq, Debug, Serialize, Deserialize)] pub enum Mode { @@ -480,20 +479,13 @@ impl Television { pub fn handle_copy_entry_to_clipboard(&mut self) { if self.mode == Mode::Channel { if let Some(entries) = self.get_selected_entries(None) { - if let Ok(mut ctx) = ClipboardContext::new() { - ctx.set_contents( - entries - .iter() - .map(|e| e.name.clone()) - .collect::>() - .join(" "), - ) - .unwrap_or_else(|_| { - error!("Could not copy to clipboard"); - }); - } else { - error!("Could not copy to clipboard"); - } + let copied_string = entries + .iter() + .map(|e| e.name.clone()) + .collect::>() + .join(" "); + + tokio::spawn(CLIPBOARD.set(copied_string)); } } } diff --git a/television/utils/clipboard.rs b/television/utils/clipboard.rs new file mode 100644 index 0000000..86c58d2 --- /dev/null +++ b/television/utils/clipboard.rs @@ -0,0 +1,177 @@ +/* +MIT License + +Copyright (c) 2023 - sxyazi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +use std::ffi::OsString; + +use crate::utils::rocell::RoCell; +use parking_lot::Mutex; + +pub static CLIPBOARD: RoCell = RoCell::new(); + +#[derive(Default)] +pub struct Clipboard { + content: Mutex, +} + +impl Clipboard { + #[cfg(unix)] + pub async fn get(&self) -> OsString { + use std::os::unix::prelude::OsStringExt; + + use tokio::process::Command; + + let all = [ + ("pbpaste", &[][..]), + ("termux-clipboard-get", &[]), + ("wl-paste", &[]), + ("xclip", &["-o", "-selection", "clipboard"]), + ("xsel", &["-ob"]), + ]; + + for (bin, args) in all { + let Ok(output) = Command::new(bin) + .args(args) + .kill_on_drop(true) + .output() + .await + else { + continue; + }; + if output.status.success() { + return OsString::from_vec(output.stdout); + } + } + self.content.lock().clone() + } + + #[cfg(windows)] + pub async fn get(&self) -> OsString { + use clipboard_win::{formats, get_clipboard}; + + let result = tokio::task::spawn_blocking(|| { + get_clipboard::(formats::Unicode) + }); + if let Ok(Ok(s)) = result.await { + return s.into(); + } + + self.content.lock().clone() + } + + #[cfg(unix)] + pub async fn set(&self, s: impl AsRef) { + use std::{ + io::{stderr, BufWriter}, + process::Stdio, + }; + + use crossterm::execute; + use tokio::{io::AsyncWriteExt, process::Command}; + + s.as_ref().clone_into(&mut self.content.lock()); + execute!( + BufWriter::new(stderr()), + osc52::SetClipboard::new(s.as_ref()) + ) + .ok(); + + let all = [ + ("pbcopy", &[][..]), + ("termux-clipboard-set", &[]), + ("wl-copy", &[]), + ("xclip", &["-selection", "clipboard"]), + ("xsel", &["-ib"]), + ]; + + for (bin, args) in all { + let cmd = Command::new(bin) + .args(args) + .stdin(Stdio::piped()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .kill_on_drop(true) + .spawn(); + + let Ok(mut child) = cmd else { continue }; + + let mut stdin = child.stdin.take().unwrap(); + if stdin + .write_all(s.as_ref().as_encoded_bytes()) + .await + .is_err() + { + continue; + } + drop(stdin); + + if child.wait().await.is_ok_and(|s| s.success()) { + break; + } + } + } + + #[cfg(windows)] + pub async fn set(&self, s: impl AsRef) { + use clipboard_win::{formats, set_clipboard}; + + let s = s.as_ref().to_owned(); + *self.content.lock() = s.clone(); + + tokio::task::spawn_blocking(move || { + set_clipboard(formats::Unicode, s.to_string_lossy()) + }) + .await + .ok(); + } +} + +#[cfg(unix)] +mod osc52 { + use std::ffi::OsStr; + + use base64::{engine::general_purpose, Engine}; + + #[derive(Debug)] + pub struct SetClipboard { + content: String, + } + + impl SetClipboard { + pub fn new(content: &OsStr) -> Self { + Self { + content: general_purpose::STANDARD + .encode(content.as_encoded_bytes()), + } + } + } + + impl crossterm::Command for SetClipboard { + fn write_ansi( + &self, + f: &mut impl std::fmt::Write, + ) -> std::fmt::Result { + write!(f, "\x1b]52;c;{}\x1b\\", self.content) + } + } +} diff --git a/television/utils/mod.rs b/television/utils/mod.rs index 80fa27a..0b88158 100644 --- a/television/utils/mod.rs +++ b/television/utils/mod.rs @@ -1,10 +1,12 @@ pub mod cache; +pub mod clipboard; pub mod command; pub mod files; pub mod hashmaps; pub mod indices; pub mod input; pub mod metadata; +pub mod rocell; pub mod shell; pub mod stdin; pub mod strings; diff --git a/television/utils/rocell.rs b/television/utils/rocell.rs new file mode 100644 index 0000000..d3758e6 --- /dev/null +++ b/television/utils/rocell.rs @@ -0,0 +1,99 @@ +/* +MIT License + +Copyright (c) 2023 - sxyazi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +use std::{ + cell::UnsafeCell, + fmt::{self, Display}, + mem, + ops::Deref, +}; + +// Read-only cell. It's safe to use this in a static variable, but it's not safe +// to mutate it. This is useful for storing static data that is expensive to +// initialize, but is immutable once. +pub struct RoCell(UnsafeCell>); + +unsafe impl Sync for RoCell {} + +impl RoCell { + #[inline] + pub const fn new() -> Self { + Self(UnsafeCell::new(None)) + } + + #[inline] + pub const fn new_const(value: T) -> Self { + Self(UnsafeCell::new(Some(value))) + } + + #[inline] + pub fn init(&self, value: T) { + debug_assert!(!self.initialized()); + unsafe { + *self.0.get() = Some(value); + } + } + + #[inline] + pub fn with(&self, f: F) + where + F: FnOnce() -> T, + { + self.init(f()); + } + + #[inline] + pub fn drop(&self) -> T { + debug_assert!(self.initialized()); + unsafe { mem::take(&mut *self.0.get()).unwrap_unchecked() } + } + + #[inline] + fn initialized(&self) -> bool { + unsafe { (*self.0.get()).is_some() } + } +} + +impl Default for RoCell { + fn default() -> Self { + Self::new() + } +} + +impl Deref for RoCell { + type Target = T; + + fn deref(&self) -> &Self::Target { + debug_assert!(self.initialized()); + unsafe { (*self.0.get()).as_ref().unwrap_unchecked() } + } +} + +impl Display for RoCell +where + T: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.deref().fmt(f) + } +}