commands/list: debounce for rapid copy operations

Tracks the entry ID currently being copied in `TuiState` to prevent
concurrent `copy_entry()` calls on the same entity. Otherwise we hit a
race condition. Fun!


Track the entry ID currently being copied in TuiState to prevent
concurrent copy_entry() calls on the same entry. Fixes database
race conditions when users trigger copy commands in rapid succession.



Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: If8e8fe56bf6dc35960e47decf59636116a6a6964
This commit is contained in:
raf 2026-03-05 14:06:12 +03:00
commit 0865a1f139
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF

View file

@ -57,6 +57,9 @@ struct TuiState {
/// Whether to show entries in reverse order (oldest first). /// Whether to show entries in reverse order (oldest first).
reverse: bool, reverse: bool,
/// ID of entry currently being copied.
copying_entry: Option<i64>,
} }
impl TuiState { impl TuiState {
@ -91,6 +94,7 @@ impl TuiState {
search_query: String::new(), search_query: String::new(),
search_mode: false, search_mode: false,
reverse, reverse,
copying_entry: None,
}) })
} }
@ -678,6 +682,13 @@ impl SqliteClipboardDb {
if actions.copy if actions.copy
&& let Some(&(id, ..)) = tui.selected_entry() && let Some(&(id, ..)) = tui.selected_entry()
{ {
if tui.copying_entry == Some(id) {
log::debug!(
"Skipping duplicate copy for entry {id} (already in \
progress)"
);
} else {
tui.copying_entry = Some(id);
match self.copy_entry(id) { match self.copy_entry(id) {
Ok((new_id, contents, mime)) => { Ok((new_id, contents, mime)) => {
if new_id != id { if new_id != id {
@ -715,6 +726,8 @@ impl SqliteClipboardDb {
.show(); .show();
}, },
} }
tui.copying_entry = None;
}
} }
} }