uttrflow / uttrflow/uttrflow-swift
Every paste, and each clip in a collection rename, rewrites the whole clipboard history file
- Dominant language
- Swift
- Stars
- 4
- Forks
- 17
- Avg merge
- 4h 27m
- Merged PRs (30d)
- 286
Description
## What happens
The history is one JSON file rewritten whole on each change, and `Docs/clipboard-store.md` accepts that for a copy. Two other paths multiply it.
1. **Every paste.** `markUsed` runs for every Insert, Copy and picture paste (`Sources/Uttrflow/AppDelegate.swift:1019-1025`). It only moves `lastUsedAt`, but it calls `save`, which re-encodes and atomically rewrites the entire history file (`Sources/UttrflowClipboard/ClipboardStore.swift:94-106`, `:475-489`).
2. **Collection operations.** Renaming a collection, deleting one and moving its clips, or deleting it with its clips loops over the clips and calls the store once per clip (`AppDelegate.swift:912-926`). Each call is a full rewrite, and a filed clip also rewrites `saved.v1.json`.
## Measured
Throwaway Release harness against a real `ClipboardStore` in a temporary folder:
| History | one ⌘C (`record`) | one paste (`markUsed`) |
|---|---|---|
| 1,000 clips, 1.8 MB file | 7.9 ms | 7.5 ms |
| 916 clips, 12.2 MB file (copied and dictation pools near their memory quotas) | 17.5 ms, 12 MB written | 17.9 ms, 12 MB written |
Renaming a 40-clip collection the way `AppDelegate` does it: 40 rewrites, **323 ms** on the 1.8 MB file. On the 12 MB file that is several hundred megabytes written for one rename.
## Why it matters
A heavy clipboard user copies and pastes hundreds of times a day. With a full history, bookkeeping alone writes gigabytes a day to the SSD, costing battery on a laptop and wear on a soldered SSD. The collection loop also holds the panel's redraw until the last write finishes.
## Acceptance criteria
- A paste does not rewrite the history file on its own. For example, `lastUsedAt` changes are batched and flushed on the next real write, on a short timer, or at quit. `Docs/clipboard-store.md` says what is lost if the app is killed first; an eviction order a few seconds stale is acceptable.
- Rename, move-out and delete of a collection are one store call and one write per file, with tests in `Tests/UttrflowClipboardTests/SavedClipsTests.swift`.
- Existing store tests pass unchanged.
Contributor guide
Research direction
Start with markUsed and save in Sources/UttrflowClipboard/ClipboardStore.swift, then trace the collection operations in Sources/Uttrflow/AppDelegate.swift. Read Docs/clipboard-store.md and the tests in Tests/UttrflowClipboardTests/SavedClipsTests.swift before deciding how usage updates are flushed. Done means paste bookkeeping no longer rewrites history alone, collection actions use one store call and write per file, and the existing store tests still pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- desktop, performance
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100