b1d98971c9
The OCR panel overflowed its container on long recognized text; it now clips, caps at 40% of the preview height, and scrolls. Ctrl+Shift+C copies an entry's text content (OCR text or QR payload for images) as plain text, and the QR/OCR panels get Copy chips.
202 lines
9.2 KiB
Markdown
202 lines
9.2 KiB
Markdown
# clipboard-history
|
|
|
|
A Raycast/vicinae-style clipboard history manager for [Omarchy](https://omarchy.org),
|
|
built as an Omarchy shell plugin. Fuzzy search over everything (content, type,
|
|
source app, date — even text inside QR codes), rich per-type previews, and
|
|
full theme integration.
|
|
|
|
<p align="center">
|
|
<img src="docs/screenshots/picker.png" alt="clipboard-history picker showing a QR code with its decoded content" width="720">
|
|
</p>
|
|
|
|
## Highlights
|
|
|
|
- **Fuzzy search over everything** — fzf-style scoring across content, source
|
|
app, and type, boosted by recency, pins, and usage. Query tokens:
|
|
- `type:image|link|text|files|code|json|color|email|html|number` (prefix match)
|
|
- `app:firefox` — fuzzy match on the source app
|
|
- `is:pinned`, `today`, `yesterday`, `week`, `<2h`, `>30s`, `<3d`
|
|
- **Rich previews, per type** — images rendered inline, QR codes show their
|
|
decoded content, colors show a swatch with hex/rgb/hsl, links show the
|
|
domain, JSON is pretty-printed, file lists show paths — every preview with
|
|
metadata chips (app, date, words/lines, size, paste counts)
|
|
- **QR codes** — copied QR images are decoded with `zbarimg`; the payload is
|
|
shown in the list, preview, and is searchable like any text clip — and if it
|
|
encodes a link, `Ctrl+O` (or the preview's "Open link" chip) opens it in the
|
|
browser directly
|
|
- **OCR search** — captured images are OCR'd with `tesseract`, so text inside
|
|
screenshots becomes fuzzy-searchable; the recognized text shows in the
|
|
preview pane and as a metadata chip
|
|
- **Rich capture** — a `wl-paste --watch` daemon records every clip with mime
|
|
type, byte size, source app (via `hyprctl`), timestamp, and image dimensions.
|
|
Text, images, and `file://` URI lists (file-manager copies) are supported;
|
|
password-manager clips and binary payloads are skipped
|
|
- **Retention control** — configure how much and how long history is kept
|
|
- **Pause/resume** — stop recording new copies without losing your history
|
|
- **Fully theme-integrated** — colors, spacing, corner radius, borders, and
|
|
the monospace font all come from the Omarchy shell's theme singletons; it
|
|
re-themes itself on `omarchy theme set`
|
|
|
|
<p align="center">
|
|
<img src="docs/screenshots/search.png" alt="fuzzy search for “omarchy” with highlighted matches" width="720">
|
|
</p>
|
|
|
|
## Install
|
|
|
|
```bash
|
|
omarchy plugin add https://github.com/alanfortlink/clipboard-history.git --enable
|
|
```
|
|
|
|
No separate dependency command is required during installation. The picker
|
|
always opens; if a helper is missing, it shows the exact package command inside
|
|
the window with a **Run in terminal** button.
|
|
|
|
Already have images in history you'd like OCR'd? One-shot backfill:
|
|
|
|
```bash
|
|
python3 scripts/backfill-ocr.py # add --lang deu for other languages
|
|
```
|
|
|
|
That's the whole install — `omarchy plugin add` clones the repo, validates the
|
|
manifest, and enables it. It replaces the built-in `omarchy.clipboard`
|
|
(restore it later with `omarchy plugin disable alanfortlink.clipboard`).
|
|
|
|
### Dependencies
|
|
|
|
All are regular Arch packages; nothing is downloaded or run at install time.
|
|
Required: `wl-clipboard`, `jq`, `python3`, `wtype` (paste into the focused
|
|
window). Optional: `zbar` (QR decoding) and `tesseract` (OCR search) — without
|
|
them the picker still works and shows the `omarchy pkg add …` command to add them.
|
|
No sudo or pkexec is required by the plugin itself.
|
|
|
|
Omarchy's default `Super+Ctrl+V` routes to it via the clone mechanism. An
|
|
existing `Super+Shift+V` binding targeting `omarchy.clipboard` routes to it too.
|
|
For a custom binding, edit the **live** config —
|
|
`~/.config/hypr/bindings.lua` on Quattro (a plain `bindings.conf` may exist
|
|
but is not sourced):
|
|
|
|
```lua
|
|
o.bind("SUPER + SHIFT + V", "Clipboard manager",
|
|
"omarchy-shell shell toggle omarchy.clipboard")
|
|
```
|
|
|
|
(If your config is still legacy `bindings.conf`: `bindd = ALT SHIFT, V, …`.)
|
|
|
|
Updating: `omarchy plugin update alanfortlink.clipboard` · Uninstall: `omarchy plugin remove alanfortlink.clipboard`
|
|
|
|
### Upgrading from a pre-1.0 install
|
|
|
|
If you installed an earlier build (plugin id `tank.clipboard`, or a symlinked
|
|
checkout via `install.sh`), remove it, reinstall from git, and repair any direct
|
|
shortcut bindings so they target Omarchy's clone-aware `omarchy.clipboard` id:
|
|
|
|
```bash
|
|
omarchy plugin remove tank.clipboard --yes # or: alanfortlink.clipboard
|
|
omarchy plugin add https://github.com/alanfortlink/clipboard-history.git --enable --yes
|
|
bash ~/.config/omarchy/plugins/alanfortlink.clipboard/scripts/configure-bindings.sh
|
|
omarchy restart shell
|
|
```
|
|
|
|
History data is preserved. `configure-bindings.sh` edits `bindings.lua` (or
|
|
`bindings.conf`) and leaves a timestamped `.bak` copy next to it; it is only
|
|
ever run when you invoke it explicitly.
|
|
|
|
## Keys
|
|
|
|
| Key | Action |
|
|
| --- | --- |
|
|
| `Ctrl+N` / `Ctrl+P` (or arrows) | navigate results |
|
|
| `Enter` | copy to clipboard and paste into the focused window |
|
|
| `Shift+Enter` | copy only |
|
|
| `Ctrl+O` | open a pure link in the browser, an image in the editor, or a file externally. Text entries stay in the picker; use `Return` to paste them. QR images open their **decoded link** in the browser; the preview pane also has clickable "Open link" chips for links and QR payloads |
|
|
| `Ctrl+Shift+C` | copy the entry's text content as plain text: for images, the OCR text (or QR payload). The QR and OCR panels also have **Copy** chips |
|
|
| `Tab` | pin/unpin |
|
|
| `Ctrl+=` | pause/resume recording |
|
|
| `Delete` | remove entry · `Shift+Delete` clear all (with confirm) |
|
|
| `Esc` | clear filter, then close |
|
|
|
|
Pause/resume is also scriptable — useful for automation or a custom binding:
|
|
|
|
```bash
|
|
omarchy-shell shell call alanfortlink.clipboard pause '{"paused":"toggle"}'
|
|
omarchy-shell shell call alanfortlink.clipboard isPaused
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Settings live on the plugin's entry in the `plugins` array of
|
|
`~/.config/omarchy/shell.json` and hot-reload on save:
|
|
|
|
```json
|
|
{
|
|
"version": 1,
|
|
"plugins": [
|
|
{
|
|
"id": "alanfortlink.clipboard",
|
|
"historyLimit": 1500,
|
|
"maxAgeDays": 30,
|
|
"maxRows": 200
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
| Key | Default | Meaning |
|
|
|-----|---------|---------|
|
|
| `historyLimit` | `1500` | max entries kept in history |
|
|
| `maxAgeDays` | `0` (forever) | drop entries older than N days (images get garbage-collected; pinned entries are exempt) |
|
|
| `maxRows` | `200` | max rows the picker shows per search |
|
|
| `qrDecode` | `true` | decode QR codes with `zbarimg` on captured images |
|
|
| `ocr` | `true` | OCR captured images with `tesseract` (skipped automatically if not installed) |
|
|
| `ocrLang` | `"eng"` | tesseract language(s), e.g. `"deu"` or `"eng+deu"` — install packs with `omarchy pkg add tesseract-data-deu` |
|
|
|
|
History lives in `~/.local/state/omarchy/clipboard-history-rich.json`; image
|
|
blobs are content-addressed under `~/.local/state/omarchy/clipboard-images/`.
|
|
|
|
## How it compares
|
|
|
|
| | built-in `omarchy.clipboard` | [sspaeti's OCR fork](https://github.com/sspaeti/omarchy-clipboard-plugin) | [Clipbasket](https://github.com/clipbasket/clipbasket-omarchy) | vicinae | **clipboard-history** |
|
|
|---|---|---|---|---|---|
|
|
| Fuzzy search | substring | + OCR text | ✓ | ✓ | content + app + type + date tokens (`type:`, `app:`, `<2h`, `today`) |
|
|
| Previews | text/image | — | — | ✓ | images, **QR payloads**, color swatches, JSON pretty-print, links, files |
|
|
| Metadata | basic | basic | SQLite | ✓ | size, source app, dims, word/line counts, pins, paste counts |
|
|
| OCR search | ✗ | ✓ (forked for it) | ✗ | ✗ | ✓ (`ocr`, searchable + preview panel) |
|
|
| Retention config | 300 cap | limit | ✓ | ✓ | `historyLimit` + `maxAgeDays` + GC |
|
|
| Pause recording | ✗ | ✗ | ? | ✓ | ✓ (in-picker + IPC) |
|
|
| Theme-integrated shell overlay | ✓ | ✓ | ✓ | own | ✓ (uses Omarchy's theme singletons) |
|
|
|
|
## Roadmap / ideas
|
|
|
|
- `autoPaste` mode swap: Enter = copy-only, Shift+Enter = paste (walker-style)
|
|
- OCR language auto-detect / confidence thresholds
|
|
- Small bar widget: last-copied item + paused indicator
|
|
- Snippet editing: edit a pinned entry's content in place
|
|
- Multi-select delete, export/import of history
|
|
- Optional per-app capture exclusions beyond the password-manager hint
|
|
|
|
## Development
|
|
|
|
```
|
|
├── manifest.json # plugin manifest (replaces omarchy.clipboard via clonedFrom)
|
|
├── Clipboard.qml # picker overlay: search, chips, list, keys, capture watchers
|
|
├── PreviewPane.qml # per-type preview + metadata chips
|
|
├── Store.js # history model: dedup, pins, retention, settings parsing
|
|
├── Fuzzy.js # query parser, fuzzy matcher, scoring, highlighting
|
|
├── Classify.js # type detection, app names, formatting, color math
|
|
├── capture.py # clipboard watcher → one JSON line per clip (QR + OCR)
|
|
├── paste-entry.sh # copy + shift-insert paste into the focused window
|
|
├── open-entry.sh # open with the right app
|
|
├── tests/ # node --test suites for the JS logic
|
|
└── scripts/ # screenshot regeneration helpers
|
|
```
|
|
|
|
- Run logic tests: `tests/run.sh`
|
|
- Validate the manifest: `omarchy plugin validate <checkout-dir>`
|
|
- Regenerate screenshots: `scripts/take-screenshots.sh` (stages demo content
|
|
and captures the picker keyboard-free over IPC)
|
|
- Hot-reload after edits: `omarchy-shell shell rescanPlugins`
|
|
|
|
## License
|
|
|
|
[MIT](LICENSE)
|