From 656709bd19a1571d06fe2e3f268c00421258c3f7 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sun, 24 May 2026 12:29:21 +0300 Subject: [PATCH 01/12] nix/modules: fix `pkgs.stdenv` deprecation in NixOS module Signed-off-by: NotAShelf Change-Id: I5b5224f809400a385e98c569e0ea63bf6a6a6964 --- nix/modules/nixos.nix | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nix/modules/nixos.nix b/nix/modules/nixos.nix index 23072a0..b577530 100644 --- a/nix/modules/nixos.nix +++ b/nix/modules/nixos.nix @@ -5,7 +5,7 @@ self: { ... }: let inherit (lib.modules) mkIf; - inherit (lib.options) mkOption mkEnableOption mkPackageOption literalMD; + inherit (lib.options) mkOption mkEnableOption mkPackageOption; inherit (lib.types) listOf str; inherit (lib.strings) concatStringsSep; inherit (lib.meta) getExe; @@ -15,7 +15,9 @@ in { options.services.stash-clipboard = { enable = mkEnableOption "stash, a Wayland clipboard manager"; - package = mkPackageOption self.packages.${pkgs.system} ["stash"] {}; + package = mkPackageOption self.packages.${pkgs.stdenv.hostPlatform.system} ["stash"] { + pkgsText = "self.packages.\${pkgs.stdenv.hostPlatform.system}"; + }; flags = mkOption { type = listOf str; @@ -28,7 +30,7 @@ in { type = str; default = ""; example = "{file}`/etc/stash/clipboard_filter`"; - description = literalMD '' + description = '' File containing a regular expression to catch sensitive patterns. The file passed to this option must contain your regex pattern with no quotes. From 384ac708ebcccbc519a22e86bc303c081fae94e9 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sun, 24 May 2026 12:52:55 +0300 Subject: [PATCH 02/12] db: remove unnecessary identity cache from `decrypt_cached` Signed-off-by: NotAShelf Change-Id: I9228809562cc9b2f7c0a9d7ece9f5ada6a6a6964 --- src/db/mod.rs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/db/mod.rs b/src/db/mod.rs index ba1c28f..90b3c13 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1218,6 +1218,11 @@ fn load_sensitive_regex() -> Option { /// previously encrypted entries permanently undecryptable, so the permanent /// cache prevents accidental passphrase changes from corrupting the /// clipboard history. +/// +/// Removing the passphrase entirely (disabling encryption) after entries have +/// been stored encrypted also renders those entries permanently unreadable. +/// There is no migration path short of wiping the database. `stash stats` +/// reports affected entries as Undecryptable. #[cfg(feature = "encryption")] fn load_encryption_passphrase() -> Option { use std::process::Command; @@ -1250,25 +1255,18 @@ fn load_encryption_passphrase() -> Option { Some(secret) } -/// Decrypt age-encrypted data using a cached scrypt identity. +/// Decrypt age-encrypted data. +/// +/// `age::scrypt::Identity::new` is cheap since it stores the passphrase only. +/// The scrypt KDF runs inside `age::decrypt` per call, on the per-file salt +/// embedded in the ciphertext header. Caching the Identity would not avoid +/// it. The passphrase itself is cached by [`load_encryption_passphrase`]. #[cfg(feature = "encryption")] fn decrypt_cached(ciphertext: &[u8]) -> Result, StashError> { - static CACHE: OnceLock>> = - OnceLock::new(); - let cache = CACHE.get_or_init(|| Mutex::new(None)); - let mut guard = cache.lock().map_err(|e| { - StashError::Decryption(format!("identity cache lock poisoned: {e}").into()) - })?; - if guard.is_none() { - let passphrase = load_encryption_passphrase().ok_or_else(|| { - StashError::Decryption("no passphrase configured".into()) - })?; - *guard = Some(age::scrypt::Identity::new(passphrase)); - } - let identity = guard - .as_ref() - .ok_or_else(|| StashError::Decryption("identity not available".into()))?; - age::decrypt(identity, ciphertext) + let passphrase = load_encryption_passphrase() + .ok_or_else(|| StashError::Decryption("no passphrase configured".into()))?; + let identity = age::scrypt::Identity::new(passphrase); + age::decrypt(&identity, ciphertext) .map_err(|e| StashError::Decryption(e.to_string().into())) } From ad70e651257ac32e26fffb456c5a956757911b99 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sun, 24 May 2026 13:32:53 +0300 Subject: [PATCH 03/12] docs: document encryption and expand filtering options documentation Signed-off-by: NotAShelf Change-Id: I2cc3b30ef1c8f1c669babdfdce501fba6a6a6964 --- README.md | 120 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 775f618..6e972bb 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,10 @@
- Lightweight & feature-rich Wayland clipboard "manager" with fast persistent history and - robust multi-media support. Stores and previews clipboard entries (text, images) - on the clipboard with a neat TUI and advanced scripting capabilities. + Lightweight & feature-rich Wayland clipboard "manager" with fast persistent + history and robust multi-media support. Stores and previews clipboard + entries (text, images) on the clipboard with a neat TUI and advanced + scripting capabilities.
@@ -52,6 +53,8 @@ with many features such as but not necessarily limited to: - Drop-in replacement for `wl-clipboard` tools (`wl-copy` and `wl-paste`) - Sensitive clipboard filtering via regex (see below) - Sensitive clipboard filtering by application (see below) +- Password manager hint filtering (`x-kde-passwordManagerHint`) +- Optional at-rest encryption for database entries using age on top of the existing features of Cliphist, which are as follows: @@ -270,8 +273,8 @@ stash db stats - `stash db vacuum`: Optimize the database using SQLite's VACUUM command, reclaiming space and improving performance. - `stash db stats`: Display database statistics including total/active/expired - entry counts, storage size, and page information. This is provided purely for - convenience and the rule of the cool. + entry counts, encrypted/undecryptable entry counts, storage size, and page + information. ### Watch clipboard for changes and store automatically @@ -357,21 +360,36 @@ sensitive pattern, using a regular expression. This is useful for preventing accidental storage of secrets, passwords, or other sensitive data. You don't want sensitive data ending up in your persistent clipboard, right? -The filter can be configured in one of three ways, as part of two separate +The filter can be configured in several ways, as part of three separate features. #### Clipboard Filtering by Entry Regex -This can be configured in one of two ways. You can use the **environment -variable** `STASTH_SENSITIVE_REGEX` to a valid regex pattern, and if the -clipboard text matches the regex it will not be stored. This can be used for -trivial secrets such as but not limited to GitHub tokens or secrets that follow -a rule, e.g. a prefix. You would typically set this in your `~/.bashrc` or -similar but in some cases this might be a security flaw. +This can be configured in several ways. The simplest is the **environment +variable** `STASH_SENSITIVE_REGEX` set to a valid regex pattern; if the +clipboard text matches, it will not be stored. Useful for trivial secrets such +as GitHub tokens or secrets that follow a rule. You would typically set this in +your `~/.bashrc` or similar, but in some cases this might be a security flaw. -The safer alternative to this is using **Systemd LoadCrediental**. If Stash is -running as a Systemd service, you can provide a regex pattern using a crediental -file. For example, add to your `stash.service`: +The less-insecure alternatives are: + +- `STASH_SENSITIVE_REGEX_FILE`: read the regex from a file path. Useful with + NixOS secrets managers like agenix or sops-nix. + + ```bash + export STASH_SENSITIVE_REGEX_FILE=/run/secrets/stash/clipboard_filter + ``` + +- `STASH_SENSITIVE_REGEX_COMMAND`: execute a shell command whose stdout is the + regex pattern. Works well with password managers. + + ```bash + export STASH_SENSITIVE_REGEX_COMMAND="pass show stash/clipboard-filter" + ``` + +The safest option is **Systemd LoadCredential**. If Stash is running as a +Systemd service, you can provide a regex pattern using a credential file. For +example, add to your `stash.service`: ```dosini LoadCredential=clipboard_filter:/etc/stash/clipboard_filter @@ -382,9 +400,9 @@ quotes). This is done automatically in the [vendored Systemd service](./contrib/stash.service). Remember to set the appropriate file permissions if using this option. -The service will check the credential file first, then the environment variable. -If a clipboard entry matches the regex, it will be skipped and a warning will be -logged. +The service will check the credential file first, then the command, then the +file path, then the environment variable. If a clipboard entry matches the +regex, it will be skipped and a warning will be logged. > [!TIP] > **Example regex to block common password patterns**: @@ -415,6 +433,72 @@ be only copied to the clipboard. > > `stash --excluded-apps Bitwarden watch` +#### Clipboard Filtering by Password Manager Hint + +Stash automatically skips entries whose clipboard offer includes the +`x-kde-passwordManagerHint` MIME type. This is the convention used by KeePassXC +and compatible password managers to signal that clipboard content is sensitive +and should not be persisted. + +No configuration is required. If the hint is present in the clipboard offer, the +entry is dropped before storage. The entry is still available in your clipboard +— it is only excluded from the persistent database. + +> [!NOTE] +> This filter only applies via the watch daemon (`stash watch`), where MIME type +> metadata is available from the Wayland clipboard protocol. Manual +> `stash store` invocations do not have this context and are not filtered. + +### Database Encryption + +Stash supports encrypting clipboard entries at rest using the +[age](https://age-encryption.org/) encryption format. + +Encryption is **opt-in** and only activates when a passphrase is configured. +When one is configured, all new entries are encrypted before storage and +decrypted transparently on retrieval. Entries stored without encryption remain +as plaintext. Only new entries written after configuring encryption are +encrypted. + +> [!WARNING] +> Removing the passphrase after encrypted entries have been stored leaves those +> entries permanently unreadable. There is no migration path short of wiping the +> database. `stash db stats` reports affected entries as Undecryptable. +> +> Full-text search (`stash delete --type query`, TUI search) operates on raw +> database contents. Encrypted entries will not match any search query. + +#### Configuration + +Provide a passphrase in one of these ways (checked in order): + +1. **Systemd LoadCredential** (safest): add to `stash.service`: + + ```dosini + LoadCredential=stash_encryption_passphrase:/etc/stash/encryption_passphrase + ``` + +2. **Command** — stdout of a shell command: + + ```bash + export STASH_ENCRYPTION_PASSPHRASE_COMMAND="pass show stash/encryption-key" + ``` + +3. **File** — path to a file containing the passphrase: + + ```bash + export STASH_ENCRYPTION_PASSPHRASE_FILE=/run/secrets/stash/encryption_passphrase + ``` + +4. **Environment variable** (least secure): + + ```bash + export STASH_ENCRYPTION_PASSPHRASE="your-secure-passphrase" + ``` + +> [!TIP] +> Back up your passphrase. Encrypted entries cannot be recovered without it. + ## Motivation I've been a long-time user of Cliphist. You can probably tell by the number of From f5789aa43d73b876b2d5cdd7c316f61637dd7e13 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sun, 24 May 2026 14:24:56 +0300 Subject: [PATCH 04/12] chore: release v0.4.0 Signed-off-by: NotAShelf Change-Id: I2a67c74f308ac2e8416fe56125bce1956a6a6964 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4435e8..49e5ff2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2937,7 +2937,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stash-clipboard" -version = "0.3.6" +version = "0.4.0" dependencies = [ "age", "arc-swap", diff --git a/Cargo.toml b/Cargo.toml index 2c46f71..33f7463 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "stash-clipboard" description = "Wayland clipboard manager with fast persistent history and multi-media support" -version = "0.3.6" +version = "0.4.0" edition = "2024" authors = [ "NotAShelf " ] license = "MPL-2.0" From fef407ec86ffcc423cf8a8e1f563471c48129da6 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sun, 24 May 2026 16:26:12 +0300 Subject: [PATCH 05/12] db: show database path in `stash db stats` Signed-off-by: NotAShelf Change-Id: I8e840d2bdf4f1ac6ecaf1d8a2954bf846a6a6964 --- src/db/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/db/mod.rs b/src/db/mod.rs index 90b3c13..7af285b 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1141,13 +1141,15 @@ impl SqliteClipboardDb { #[cfg(not(feature = "encryption"))] let undecryptable: i64 = encrypted; + let db_path = self.db_path.display(); Ok(format!( "Database Statistics:\n\nEntries:\nTotal: \ {total}\nActive: {active}\nExpired: \ {expired}\nWith TTL: \ {with_expiration}\nEncrypted: \ {encrypted}\nUndecryptable: \ - {undecryptable}\n\nStorage:\nSize: {size_mb:.2} MB \ + {undecryptable}\n\nStorage:\nPath: \ + {db_path}\nSize: {size_mb:.2} MB \ ({size_bytes} bytes)\nPages: {page_count}\nPage size: \ {page_size} bytes" )) From 3f2e34b8eac5ed4af14368e378f94714c42fc079 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sun, 24 May 2026 16:33:26 +0300 Subject: [PATCH 06/12] db: allow forcefully expiring entries with valid TTL Signed-off-by: NotAShelf Change-Id: Ie7ca7b88cf912e8f71fb2d04481bd9996a6a6964 --- src/db/mod.rs | 11 +++++++++++ src/main.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/db/mod.rs b/src/db/mod.rs index 7af285b..41aec9f 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1024,6 +1024,17 @@ impl SqliteClipboardDb { } /// Clean up all expired entries. Returns count deleted. + pub fn expire_ttl_entries(&self) -> Result { + self + .conn + .execute( + "UPDATE clipboard SET is_expired = 1 WHERE expires_at IS NOT NULL AND \ + (is_expired IS NULL OR is_expired = 0)", + [], + ) + .map_err(|e| StashError::Trim(e.to_string().into())) + } + pub fn cleanup_expired(&self) -> Result { let now = Self::now(); self diff --git a/src/main.rs b/src/main.rs index f006d36..a711c8d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -169,6 +169,13 @@ enum DbAction { ask: bool, }, + /// Immediately expire all entries with a TTL + Expire { + /// Ask for confirmation before expiring + #[arg(long)] + ask: bool, + }, + /// Optimize database using VACUUM Vacuum, @@ -406,6 +413,28 @@ fn main() -> eyre::Result<()> { } } }, + DbAction::Expire { ask } => { + let should_proceed = !ask + || confirm( + "Are you sure you want to immediately expire all entries with \ + a TTL?", + ); + if should_proceed { + match db.expire_ttl_entries() { + Ok(0) => { + println!("no entries with a TTL to expire"); + }, + Ok(count) => { + println!("marked {count} entries as expired"); + }, + Err(e) => { + log::error!("failed to expire entries: {e}"); + }, + } + } else { + log::info!("db expire command aborted by user."); + } + }, DbAction::Vacuum => { match db.vacuum() { Ok(()) => { From 9120e57926ddd8d2b744f89a423e3253534efb5c Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sun, 24 May 2026 18:47:24 +0300 Subject: [PATCH 07/12] clipboard: clear stale serving PID; fix persistence restart Fixes #99 where persistence silently stops after the first entry because `SERVING_PID` was never reset in the parent after the child exited. Signed-off-by: NotAShelf Change-Id: Id41e16980c45e35be2a984e6f85b96e76a6a6964 --- src/clipboard/persist.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/clipboard/persist.rs b/src/clipboard/persist.rs index f5312a7..9ca9dc7 100644 --- a/src/clipboard/persist.rs +++ b/src/clipboard/persist.rs @@ -22,9 +22,25 @@ static SERVING_PID: AtomicI32 = AtomicI32::new(0); /// Get the current serving PID if any. Used by the watch loop to avoid /// duplicate persistence processes. +/// +/// Probes the stored PID with `kill(pid, 0)` to detect children that have +/// already exited (SIGCHLD is ignored so we never get reaped notifications). +/// A stale PID is cleared and `None` is returned. pub fn get_serving_pid() -> Option { let pid = SERVING_PID.load(Ordering::SeqCst); - if pid != 0 { Some(pid) } else { None } + if pid == 0 { + return None; + } + + // Signal 0 = existence check, no signal sent. Returns 0 if alive, + // -1 (ESRCH) if the PID is gone. + if unsafe { libc::kill(pid, 0) } == 0 { + Some(pid) + } else { + let _ = + SERVING_PID.compare_exchange(pid, 0, Ordering::SeqCst, Ordering::SeqCst); + None + } } /// Result type for persistence operations. @@ -157,6 +173,18 @@ unsafe fn fork_and_serve(prepared: PreparedCopy) -> PersistenceResult<()> { libc::signal(libc::SIGCHLD, libc::SIG_IGN); } + // Replace any prior serving child: a new clipboard entry supersedes the + // old offer (the compositor will invalidate it anyway the moment the new + // selection is taken). Without this, the old child lingers serving stale + // data until MAX_SERVE_REQUESTS or invalidation. + let prior = SERVING_PID.swap(0, Ordering::SeqCst); + if prior > 0 && unsafe { libc::kill(prior, 0) } == 0 { + unsafe { + libc::kill(prior, libc::SIGTERM); + } + log::debug!("terminated prior persistence child (pid: {prior})"); + } + match unsafe { libc::fork() } { 0 => { // Child process - clear serving PID From a50298b11898c960d8e09f8d0b6dbad27fe78c1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 May 2026 21:08:00 +0000 Subject: [PATCH 08/12] build(deps): bump crane from `6d015ea` to `edb3889` Bumps [crane](https://github.com/ipetkov/crane) from `6d015ea` to `edb3889`. - [Release notes](https://github.com/ipetkov/crane/releases) - [Commits](https://github.com/ipetkov/crane/compare/6d015ea29630b7ad2402841386da2cb617a470a7...edb38893982a3338972bb4a2ec7ce7c29ba10fd9) --- updated-dependencies: - dependency-name: crane dependency-version: edb38893982a3338972bb4a2ec7ce7c29ba10fd9 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index a2247e8..78e3571 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "crane": { "locked": { - "lastModified": 1778106249, - "narHash": "sha256-cM/AuKy5tMhwOOQIbha8ZRRMHVfNf7cv2aljIw+qoCg=", + "lastModified": 1779130139, + "narHash": "sha256-BLrtr42azquO7MdGFU5a7KiMl3YpFlTeIXqy1fT5GlQ=", "owner": "ipetkov", "repo": "crane", - "rev": "6d015ea29630b7ad2402841386da2cb617a470a7", + "rev": "edb38893982a3338972bb4a2ec7ce7c29ba10fd9", "type": "github" }, "original": { From 2f5cf1dd2ec964e545ad5795d69f27941d9eedfe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 14:53:40 +0000 Subject: [PATCH 09/12] build(deps): bump crane from `edb3889` to `6823b49` Bumps [crane](https://github.com/ipetkov/crane) from `edb3889` to `6823b49`. - [Release notes](https://github.com/ipetkov/crane/releases) - [Commits](https://github.com/ipetkov/crane/compare/edb38893982a3338972bb4a2ec7ce7c29ba10fd9...6823b493a0bc2142082075576efa6633b537197e) --- updated-dependencies: - dependency-name: crane dependency-version: 6823b493a0bc2142082075576efa6633b537197e dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 78e3571..7fe4959 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "crane": { "locked": { - "lastModified": 1779130139, - "narHash": "sha256-BLrtr42azquO7MdGFU5a7KiMl3YpFlTeIXqy1fT5GlQ=", + "lastModified": 1780532242, + "narHash": "sha256-D+BsdpxmtUwtqGoY0IXPhHgTlmqgcZKCEo1oMyn7ep0=", "owner": "ipetkov", "repo": "crane", - "rev": "edb38893982a3338972bb4a2ec7ce7c29ba10fd9", + "rev": "59a82a1222dd3b2080b5cc52a1a2e8d5f1b77f37", "type": "github" }, "original": { From 65be1f8e08e41d05f92d78a20b8302f08e6de496 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Wed, 17 Jun 2026 11:09:19 +0300 Subject: [PATCH 10/12] nix: bump nixpkgs Signed-off-by: NotAShelf Change-Id: I6840d9cbf2d8d05e627e69400ef8c4de6a6a6964 --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 7fe4959..f5e6ab1 100644 --- a/flake.lock +++ b/flake.lock @@ -17,11 +17,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1778869304, - "narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=", + "lastModified": 1781577229, + "narHash": "sha256-lrp67w8AulE9Ks53n27I45ADSzbOCn4H+CNW1Ck8B+8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d233902339c02a9c334e7e593de68855ad26c4cb", + "rev": "567a49d1913ce81ac6e9582e3553dd90a955875f", "type": "github" }, "original": { From 8c339240c7f4f8e75f46af3940239e85bfa69a10 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Wed, 17 Jun 2026 11:09:23 +0300 Subject: [PATCH 11/12] build: bump dependencies Signed-off-by: NotAShelf Change-Id: Ia2b269b736e8bcc3f798fd6c1b4a562c6a6a6964 --- Cargo.lock | 203 +++++++++++++++++++++++++++++++++++------------------ Cargo.toml | 18 ++--- 2 files changed, 145 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 49e5ff2..f875bb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -141,6 +141,15 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "arc-swap" version = "1.9.1" @@ -389,9 +398,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "block-buffer" @@ -430,6 +439,12 @@ version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + [[package]] name = "bytemuck" version = "1.25.0" @@ -504,9 +519,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -536,9 +551,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", @@ -635,6 +650,12 @@ dependencies = [ "libc", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -647,7 +668,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "crossterm_winapi", "derive_more", "document-features", @@ -834,7 +855,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "block2", "libc", "objc2", @@ -1006,6 +1027,12 @@ dependencies = [ "regex", ] +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + [[package]] name = "fastrand" version = "2.4.1" @@ -1311,14 +1338,19 @@ name = "hashbrown" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "hashlink" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" +checksum = "a5081f264ed7adee96ea4b4778b6bb9da0a7228b084587aa3bd3ff05da7c5a3b" dependencies = [ - "hashbrown 0.16.1", + "hashbrown 0.17.0", ] [[package]] @@ -1592,7 +1624,7 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6654738b8024300cf062d04a1c13c10c8e2cea598ec1c47dc9b6641159429756" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "crossterm", "dyn-clone", "unicode-segmentation", @@ -1727,6 +1759,12 @@ version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + [[package]] name = "libredox" version = "0.1.16" @@ -1738,9 +1776,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.37.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" +checksum = "f6c19a05435c21ac299d71b6a9c13db3e3f47c520517d58990a462a1397a61db" dependencies = [ "cc", "pkg-config", @@ -1753,7 +1791,7 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", ] [[package]] @@ -1785,29 +1823,31 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" [[package]] name = "lru" -version = "0.16.3" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" +checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9" dependencies = [ - "hashbrown 0.16.1", + "hashbrown 0.17.0", ] [[package]] name = "mac-notification-sys" -version = "0.6.12" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a16783dd1a47849b8c8133c9cd3eb2112cfbc6901670af3dba47c8bbfb07d3" +checksum = "fd604973958ddcc11b561193c0fb96ba146506ef2f231ef2e7c35fd2cbc9beca" dependencies = [ "cc", + "log", "objc2", "objc2-foundation", "time", + "uuid", ] [[package]] @@ -1890,7 +1930,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "cfg-if", "cfg_aliases", "libc", @@ -1903,7 +1943,7 @@ version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "cfg-if", "cfg_aliases", "libc", @@ -1930,9 +1970,9 @@ dependencies = [ [[package]] name = "notify-rust" -version = "4.17.0" +version = "4.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50ff2e74231b72c832d82982193b417f230945be6bdb5575b251d941d31adb00" +checksum = "c5b4c1b4f2aa9f25f63a7a49d3dd0ed567b3670da15330a66b29434be899b891" dependencies = [ "futures-lite", "log", @@ -1992,7 +2032,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "dispatch2", "objc2", ] @@ -2009,7 +2049,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "block2", "libc", "objc2", @@ -2084,6 +2124,30 @@ version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" +[[package]] +name = "palette" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +dependencies = [ + "approx", + "fast-srgb8", + "libm", + "palette_derive", +] + +[[package]] +name = "palette_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "parking" version = "2.2.1" @@ -2463,9 +2527,9 @@ dependencies = [ [[package]] name = "ratatui" -version = "0.30.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1ce67fb8ba4446454d1c8dbaeda0557ff5e94d39d5e5ed7f10a65eb4c8266bc" +checksum = "1695748e3a735b34968c887ceea5a380b43545903868ae8f5b666593100f6b68" dependencies = [ "instability", "ratatui-core", @@ -2473,21 +2537,25 @@ dependencies = [ "ratatui-macros", "ratatui-termwiz", "ratatui-widgets", + "serde", ] [[package]] name = "ratatui-core" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293" +checksum = "42d3603f354bba8c595fa47860e60142d7372b7210c27044c6a7d0e1a4336b44" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "compact_str", - "hashbrown 0.16.1", + "critical-section", + "hashbrown 0.17.0", "indoc", "itertools", "kasuari", "lru", + "palette", + "serde", "strum", "thiserror 2.0.18", "unicode-segmentation", @@ -2497,9 +2565,9 @@ dependencies = [ [[package]] name = "ratatui-crossterm" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "577c9b9f652b4c121fb25c6a391dd06406d3b092ba68827e6d2f09550edc54b3" +checksum = "2b2867bedcbd6a690ca4f8672a687b730ec07660c79844517b084311b529980c" dependencies = [ "cfg-if", "crossterm", @@ -2509,9 +2577,9 @@ dependencies = [ [[package]] name = "ratatui-macros" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f1342a13e83e4bb9d0b793d0ea762be633f9582048c892ae9041ef39c936f4" +checksum = "80fac59720679490d89d200df411faa249be728681adcabed3d047ae72c48f1d" dependencies = [ "ratatui-core", "ratatui-widgets", @@ -2519,9 +2587,9 @@ dependencies = [ [[package]] name = "ratatui-termwiz" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f76fe0bd0ed4295f0321b1676732e2454024c15a35d01904ddb315afd3d545c" +checksum = "386b8ff8f74ed749509391c56d549761a2fcdb408e1f42e467286bcb7dac8967" dependencies = [ "ratatui-core", "termwiz", @@ -2529,17 +2597,18 @@ dependencies = [ [[package]] name = "ratatui-widgets" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7dbfa023cd4e604c2553483820c5fe8aa9d71a42eea5aa77c6e7f35756612db" +checksum = "7ef4f17dd7ac3abf5adc2b920a03c61eee4bfe6a88fa5191936895525371d79c" dependencies = [ - "bitflags 2.11.0", - "hashbrown 0.16.1", + "bitflags 2.13.0", + "hashbrown 0.17.0", "indoc", "instability", "itertools", "line-clipping", "ratatui-core", + "serde", "strum", "time", "unicode-segmentation", @@ -2552,7 +2621,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", ] [[package]] @@ -2568,9 +2637,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -2591,9 +2660,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rsqlite-vfs" @@ -2607,11 +2676,11 @@ dependencies = [ [[package]] name = "rusqlite" -version = "0.39.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2b0146dd9661bf67bb107c0bb2a55064d556eeb3fc314151b957f313bcd4e" +checksum = "11438310b19e3109b6446c33d1ed5e889428cf2e278407bc7896bc4aaea43323" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -2687,7 +2756,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "errno", "libc", "linux-raw-sys", @@ -2803,9 +2872,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", @@ -2987,18 +3056,18 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" dependencies = [ "heck", "proc-macro2", @@ -3099,7 +3168,7 @@ checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" dependencies = [ "anyhow", "base64 0.22.1", - "bitflags 2.11.0", + "bitflags 2.13.0", "fancy-regex", "filedescriptor", "finl_unicode", @@ -3376,9 +3445,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-truncate" @@ -3584,7 +3653,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "hashbrown 0.15.5", "indexmap", "semver", @@ -3609,7 +3678,7 @@ version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "log", "rustix", "wayland-backend", @@ -3622,7 +3691,7 @@ version = "0.32.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -3634,7 +3703,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -3975,7 +4044,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", + "bitflags 2.13.0", "indexmap", "log", "serde", diff --git a/Cargo.toml b/Cargo.toml index 33f7463..fbacc09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ authors = [ "NotAShelf " ] license = "MPL-2.0" readme = true repository = "https://github.com/notashelf/stash" -rust-version = "1.91.0" +rust-version = "1.95.0" [[bin]] name = "stash" # actual binary name for Nix, Cargo, etc. @@ -18,7 +18,7 @@ age = { version = "0.11.3", optional = true } arc-swap = { version = "1.9.1", optional = true } base64 = "0.22.1" blocking = "1.6.2" -clap = { version = "4.6.0", features = [ "derive", "env" ] } +clap = { version = "4.6.1", features = [ "derive", "env" ] } clap-verbosity-flag = "3.0.4" color-eyre = "0.6.5" crossterm = "0.29.0" @@ -29,17 +29,17 @@ humantime = "2.3.0" imagesize = "0.14.0" inquire = { version = "0.9.4", default-features = false, features = [ "crossterm" ] } libc = "0.2.186" -log = "0.4.29" +log = "0.4.32" mime-sniffer = "0.1.3" -notify-rust = { version = "4.17.0", optional = true } -ratatui = "0.30.0" -regex = "1.12.3" -rusqlite = { version = "0.39.0", features = [ "bundled" ] } +notify-rust = { version = "4.18.0", optional = true } +ratatui = "0.30.1" +regex = "1.12.4" +rusqlite = { version = "0.40.1", features = [ "bundled" ] } serde = { version = "1.0.228", features = [ "derive" ] } -serde_json = "1.0.149" +serde_json = "1.0.150" smol = "2.0.2" thiserror = "2.0.18" -unicode-segmentation = "1.13.2" +unicode-segmentation = "1.13.3" unicode-width = "0.2.2" wayland-client = { version = "0.31.14", features = [ "log" ], optional = true } wayland-protocols-wlr = { version = "0.3.12", default-features = false, optional = true } From 6413449c45333a64968bb338b35a00ecb05b1ed7 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Wed, 17 Jun 2026 11:11:15 +0300 Subject: [PATCH 12/12] various: fix `collapsable-if` clippy warnings Signed-off-by: NotAShelf Change-Id: I379d9b83a86707a59d8fdf8199a22c426a6a6964 --- src/commands/list.rs | 14 ++++++-------- src/multicall/wl_paste.rs | 8 +++----- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/commands/list.rs b/src/commands/list.rs index 3a0b3b9..b926537 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -396,18 +396,16 @@ impl SqliteClipboardDb { // Normal mode navigation commands match (key.code, key.modifiers) { (KeyCode::Char('q') | KeyCode::Esc, _) => actions.quit = true, - (KeyCode::Down | KeyCode::Char('j'), _) => { + (KeyCode::Down | KeyCode::Char('j'), _) // Cap at +1 per frame for smooth scrolling - if actions.net_down < 1 { + if actions.net_down < 1 => { actions.net_down += 1; - } - }, - (KeyCode::Up | KeyCode::Char('k'), _) => { + }, + (KeyCode::Up | KeyCode::Char('k'), _) // Cap at -1 per frame for smooth scrolling - if actions.net_down > -1 { + if actions.net_down > -1 => { actions.net_down -= 1; - } - }, + }, (KeyCode::Enter, _) => actions.copy = true, (KeyCode::Char('D'), KeyModifiers::SHIFT) => { actions.delete = true; diff --git a/src/multicall/wl_paste.rs b/src/multicall/wl_paste.rs index 5a893d6..50cd4e9 100644 --- a/src/multicall/wl_paste.rs +++ b/src/multicall/wl_paste.rs @@ -474,13 +474,11 @@ fn handle_regular_paste( || types == "application/x-sh" }; - if !args.no_newline && is_text_content && !buf.ends_with(b"\n") { - if let Err(e) = out.write_all(b"\n") { - if e.kind() != io::ErrorKind::BrokenPipe { + if !args.no_newline && is_text_content && !buf.ends_with(b"\n") + && let Err(e) = out.write_all(b"\n") + && e.kind() != io::ErrorKind::BrokenPipe { bail!("failed to write newline to stdout: {e}"); } - } - } }, Err(PasteError::NoSeats) => { bail!("no seats available (is a Wayland compositor running?)");