Commit graph

68 commits

Author SHA1 Message Date
bb8e882565
mime: expand test coverage
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I3f17b98ad68f17ebcf9554e5e88f62676a6a6964
2026-02-01 11:55:02 +03:00
ff2f272055
mime: refactor mime detection to separate module; streamline
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I489054d2537a4c0de32d79f793478c206a6a6964
2026-01-23 23:13:01 +03:00
b00e9b5f3a
watch: clear clipboard when expired entry content matches current clipboard
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I4bede5db16cea993ed8e8591e8d198d56a6a6964
2026-01-22 18:27:24 +03:00
5731fb08a5
cli: add db subcommand
Adds a `db` subcommand with `DbAction` for three new database
operations: wipe, vacuum and stats. We can extend this database later,
but this is a very good start for now and plays nicely with the
`--expired` flag. This soft-deprecates `stash wipe` in favor of a `stash
db wipe` with the addition of a new `--expired` flag that wipes the
expired entries only. 

The `list` subcommand has also been refactored to allow for a similar
`--expired` flag that lists only expired entries.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I34107880185d231d207b0dab7782d5d96a6a6964
2026-01-22 16:56:44 +03:00
2e555ee043
commands/list: add include_expired parameter for filtering
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ia1ab13345cfa5e2cf9a92f8b32a6a9826a6a6964
2026-01-22 16:56:43 +03:00
b070d4d93d
watch: implement soft-delete behaviour for expired entries
The previous `--expire-after` flag behave more like *delete* after
rather than *expire*. This fixes that, and changes the behaviour to
excluding expired entries from list commands and already-marked expired
entries from expiration queue. Updates log messages accordingly.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ib162dff3a76e23edcdfbd1af13b01b916a6a6964
2026-01-22 16:56:42 +03:00
d40b547c07
db: add is_expired column and implement vacuum/stats commands
Migrates schema to v5; `is_expired` column is added with partial index
and `include_expired` parameter to `list_entries()` and `list_json()`
methods. Also adds `vacuum()` and `stats()` methods for SQlite
"administration", and removes `next_sequence()` from trait and impl.

This has been a valuable addition to stash, as the database is now *less
abstract* in the sense that user is made aware of its presence (stash
wipe -> stash db wipe) and can modify it.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Icfab67753d7f18e3798c0a930b16d05e6a6a6964
2026-01-22 16:56:41 +03:00
f4936e56ff
cli: add --expire-after flag to watch and --expired flag to list
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I833e7bfaecb5e3254d2ea16f2b880e246a6a6964
2026-01-22 16:56:40 +03:00
dd7a55c760
watch: implement expiration queue w/ sub-second precision
This adds a Neg wrapper struct for min-heap behaviour on BinaryHeap
which has proven *really* valuable. Also modify `watch()` to take the
`expire_after` argument for various new features. See my previous commit
for what is actually new.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I8705d404eae5d93ad48f738a24f698196a6a6964
2026-01-22 16:56:39 +03:00
71fc1ff40f
db: add `expires_at column and expiration management methods
Schema v4: add expires_at REAL column with partial index for NULL values

Other relevant methods that were added:

- `now()` for Unix timestamp with sub-second precision
- `cleanup_expired()` to remove all expired entries
- `get_expired_entries()` for for diagnostic output (`stash list --expired`)
- `get_next_expiration()` for heap initialization
- `set_expiration()` to update expiration timestamp

This feature has proven larger than I had anticipated (and hoped) but
that's the reality of dealing with databases. Some of the methods are
slightly redundant but it helps keep tracing the code manageable and
semantically correct. We'll probably not regret those later. Probably.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ie9e5b0767673e74389b8e59c466afd946a6a6964
2026-01-22 16:56:38 +03:00
047445b143
db: distinguish HEIC from HEIF in mime type detection
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I1a25c6d30fde6b4cc33c2a1666b2e1606a6a6964
2026-01-22 13:48:30 +03:00
c65073e0d1
db: rewrite migration with transactional schema versioning
This makes Stash's database handler a bit more robust. The changes
started as me trying to add an entry expiry, but I've realized that the
database system is a little fragile and it assumed the database does not
change, ever. Well that's not true, it does change and when it does
there's a chance that everything implodes.

We now wrap migrations in transaction for atomicity and track version
via PRAGMA user_version (0 -> 3). We also check column existence before
ALTER TABLE and use `last_insert_rowid()` instead of `next_sequence()`.

Last but not least, a bunch of regression tests have been added to the
database system because I'd rather not discover regressions in
production.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ifeab42b0816a5161d736767cb82065346a6a6964
2026-01-22 13:41:58 +03:00
3165543580
commands: prevent usize underflow when navigating empty entry list
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I0432dcc88b22226772f6bb6e05cc64d36a6a6964
2026-01-22 13:41:57 +03:00
20b6a12461
stash: make db module public for test visibility
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I5f75e6515114e7479a3fe63771a4e7fe6a6a6964
2026-01-22 13:41:56 +03:00
59423f9ae4
list: add content_hash and last_accessed tracking with de-duplication
Adds a `content_hash` column and index for deduplication, and a
`last_accessed` column & index for time tracking. We now de-duplicate on
copy by not copying if present, but instead bubbling up matching entry.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Icbcdbd6ac28bbb21324785cae30911f96a6a6964
2026-01-22 13:41:54 +03:00
f2274aa524
multicall: auto-select MIME type more intelligently when not specified
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Idfd5ab25079161d694bda429e70500a16a6a6964
2025-12-23 10:11:28 +03:00
bbfe583423
multicall: prevent newline corruption of binary data in wl-copy
Previously we unconditionally appended a newline to all clipboard
contents, which ended up corrupting binary files like PNG images when
using shell redirection (e.g., `wl-paste > file.png`). Now we
intelligently (in quotes) detect content type via MIME type and only
append newlines to text-based content such as `text/*`,
`application/json` and so on. Binary data on another hand is written
exactly as it is. Falls back to UTF-8 validation when MIME type is
unavailable.

On paper this is also fully backwards compatible; text content still
gets newline by default *unless* the `--no-newline` flag is used.

Fixes #52

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I8b1e6f7013d081150be761820cafd1926a6a6964
2025-12-23 09:41:19 +03:00
raf
1f0312b2f6
Merge pull request #56 from NotAShelf/notashelf/push-umuwyuqntslp
various: bump dependencies
2025-12-22 17:14:53 +03:00
c2182d21dc
chore: bump dependencies; fix lifetime warnings for Rust 1.90+
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: If755ceefb970311c7660118cb2019c2c6a6a6964
2025-12-22 16:59:12 +03:00
a68946d54d
various: fix clippy lints
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I4bb649a5161460d8794dc5c93baa6cc46a6a6964
2025-11-13 00:05:52 +03:00
2d8ccf2a4f
multicall: go back to forking solution
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I2a24a3c7efc41fc45c675fd98e08782e6a6a6964
2025-11-13 00:05:48 +03:00
61ff65e9e8
stash: make log messages lowercase
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I45a9055b6bc3bfbf2179627470d0cedd6a6a6964
2025-10-28 13:02:59 +03:00
d59ac77b9f
stash: utilize clap for multicall functionality; simplify CLI handler
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I84d9f46bb9bba0e893aa4f99d6ff48f76a6a6964
2025-10-28 12:40:17 +03:00
78acc38044
multicall: cleanup; modularize
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I658f22fdf983777354a5beb32df631916a6a6964
2025-10-27 11:11:13 +03:00
955a5d51f8
multicall: cleanup; match wl-copy/wl-paste interfaces more closely
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I8cc05c0141cccff8378ef4fd83ccf77d6a6a6964
2025-10-25 08:38:53 +03:00
78fa23a764
multicall: remove program name prefixes from log and error messages
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964f65a0f1e473a50abfa985365ad8f1fa1
2025-10-09 14:44:45 +03:00
6496d3963d
stash: add multicall support for stash-copy and stash-paste
We can finally tell the users that they can uninstall `wl-copy` and
`wl-paste` on their systems. Stash now somewhat supports being invoked
under the names `stash-copy` and `stash-paste` to fully reimplement the
functionality of `wl-copy` and `wl-paste` respectively.

A build wrapper has been added generate symlinks for `stash-copy`, `stash-paste`,
`wl-copy`, and `wl-paste`. `wl-copy` and `wl-paste` links are provided
only for backwards compatibility, but they will not go away anytime
soon.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964463b35427cb720fbab68b252944cc90c
2025-10-09 14:40:54 +03:00
f8440926b1
list: log clipboard copy errors and update notification message
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a69649bdd37a44f254d520e33a54634958ada
2025-10-09 11:45:37 +03:00
d8b1ac1f37
list: properly error notification if clipboard copy fails
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a696459d7fbc344545daeead6164cad5cde6f
2025-10-09 11:45:36 +03:00
4c0782f80e
list: add clipboard actions for delete and copy; notify
This adds an optional dependency on notify-rust, which we use to display
notifications when an entry is deleted or copied. If the user thinks a
TUI using desktop notifications is *not* desirable, it can be disabled
with the `notifications` feature flag.

We now support copying entries to the clipboard with `Enter` and
deleting entries with `Shift+D`. Both of those will show notifications.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a69642d0c13a1359b3b51125cc4b691cd5679
2025-10-09 11:08:50 +03:00
a41d72fb6b
stash: refactor error handling and entry deduplication
This includes breaking changes to the database entries, where we have
started deduplicating based on hashes instead of full entries. Entry
collisions are possible, but highly unlikely.

Additionally we use `Box<str>` for error variants to reduce allocations.
This is *yet* to give me a non-marginal performance benefit but doesn't
hurt to be more correct.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964d0a33392da61372214ca3088551564ac
2025-09-19 14:08:15 +03:00
d05ad311a9
wayland: remove closed toplevels on event
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a69644f5e067b3533a7f62c42d4a6d01be00b
2025-09-19 14:08:14 +03:00
36c183742d
stash: blocking persistent entries by window class
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964061bd97b4ffc4e84d835072331a966c6
2025-09-19 11:22:58 +03:00
c9a73b462d
commands: more consistent error propagation
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a69647a0eb8de028e4251465fbb94f0a14cef
2025-08-20 18:38:05 +03:00
ae98cc0b86
stash: replace atty with is_terminal from std::io
It's deprecated, oops.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a69646dc5a20ff1fde23ea9a846a7a3fdd16a
2025-08-20 18:38:04 +03:00
Rexiel Scarlet
ef0d05cbad
reset auto increment on stash wipe 2025-08-20 18:53:46 +04:00
b1a220400d
stash: add help text for cliphist compat flags
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964aa5c4ab66d13fe6e0d38400cdde5de1a
2025-08-20 11:06:53 +03:00
1ed518a3b6
stash: move import logic into stash::commmands
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964f8fb8c9b14049ba3a343bb453ca59004
2025-08-20 11:06:52 +03:00
f39937d3ca
stash: import all entries by default; log if db import fails
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964804698d2e83a37ec2688e9c126cf412b
2025-08-20 09:57:45 +03:00
6a5cd9b95d
treewide: format with rustfmt
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a69642c2865f41a4b141ddf39a198a3fc2e09
2025-08-20 09:57:44 +03:00
47fd5e4964
db: support other image formats supported by imagesize
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a69646b72b8bc223fe9729be3dbefbae2b353
2025-08-15 08:04:36 +03:00
7c26947437
commands/list: resolve clippy warnings
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964e1bb8c22b5026ce65889e3aec1b90a71
2025-08-15 08:04:35 +03:00
83d45c6414
list: if we're in a TTY, output data in a TUI
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a696493f2e7ca911b6c1e2692b67f357a4b6b
2025-08-15 08:04:24 +03:00
0547376a9e
chore: apply clippy fixes; suppress "too many lines" lint
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a696476135218b9979677c66c4be4d96aced8
2025-08-14 17:31:26 +03:00
f3089148e0
db: allow explicitly skipping sensitive entries
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964ed1deaac0215ae9c6f4c70cfdc50164d
2025-08-14 17:24:20 +03:00
86001652cd
stash: allow confirming destructive operations with --ask
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a69644c23734a8b088e20473d381390d532b4
2025-08-14 17:24:01 +03:00
f6bf5586ad
import: nesting is ew yuck
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964becfe6f31b0411110b75d4cdfe2b9c63
2025-08-14 10:53:40 +03:00
64c923480e
decode: fallback to relaying current clipboard to stdout on failure
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a696451def3e367afa9e8b0dd6ae626906e53
2025-08-13 18:46:02 +03:00
db6a962c75
stash: create database directory automatically if missing
Oops.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964866a1711971322c81ea194aa062466da
2025-08-13 17:07:06 +03:00
9d0ad95e07
db: treat valid UTF-8 entries as text/plain
Makes JSON output more... servicable.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6a6a6964f642a02e990979f93f53a8b69764b469
2025-08-12 23:01:12 +03:00