Fix invisible picker and show dependency setup in UI

This commit is contained in:
2026-09-06 00:03:09 +01:00
parent ac3b5ef4dc
commit 4e0cd0ab36
4 changed files with 55 additions and 37 deletions
+44 -25
View File
@@ -61,7 +61,11 @@ Item {
// ------------------------------------------------------------ lifecycle // ------------------------------------------------------------ lifecycle
function open() { function open() {
// Always show the picker first. Dependency checks are asynchronous and
// only update the in-window banner; they never block or replace the UI.
root.opened = true root.opened = true
root.depsChecked = false
root.checkDeps()
root.filterText = "" root.filterText = ""
root.typeFilter = "" root.typeFilter = ""
root.selectedIndex = 0 root.selectedIndex = 0
@@ -334,30 +338,47 @@ Item {
// Missing-helper state surfaced IN the picker: banner with the exact // Missing-helper state surfaced IN the picker: banner with the exact
// command and a "Run in terminal" button. Nothing launches on its own. // command and a "Run in terminal" button. Nothing launches on its own.
property bool depsChecked: false property bool depsChecked: false
property var missingDeps: [] // [{ name, command }] property var missingDeps: [] // [{ name, packages }]
property string depsPendingSlot: ""
function checkDeps() { function checkDeps() {
if (root.depsChecked) return if (root.depsChecked || depsProc.running) return
root.depsChecked = true root.depsChecked = true
if (root.qrDecode) { var checks = [
depsProc.slot = "qr" "python3|Clipboard capture|python3",
depsProc.command = ["bash", "-c", "command -v zbarimg >/dev/null 2>&1 && echo ok || echo missing"] "jq|Paste and open actions|jq",
depsProc.running = true "wl-copy|Clipboard access|wl-clipboard",
"wtype|Paste into the active window|wtype"
]
if (root.qrDecode) checks.push("zbarimg|QR decode|zbar")
if (root.ocr) checks.push("tesseract|OCR search|tesseract tesseract-data-eng")
var script = ""
for (var i = 0; i < checks.length; i++) {
var fields = checks[i].split("|")
script += "command -v " + fields[0] + " >/dev/null 2>&1 || printf '%s\\n' '" + checks[i] + "';"
} }
if (root.ocr) { depsProc.command = ["bash", "-c", script]
depsProc.slot = "ocr"
depsProc.command = ["bash", "-c", "command -v tesseract >/dev/null 2>&1 && echo ok || echo missing"]
depsProc.running = true depsProc.running = true
} }
}
function depResult(slot, line) { function depResult(output) {
if (String(line).trim() !== "missing") return var missing = []
if (slot === "qr") { var lines = String(output || "").trim().split("\n")
root.missingDeps.push({ name: "QR decode", command: "omarchy pkg add zbar" }) for (var i = 0; i < lines.length; i++) {
} else if (slot === "ocr") { if (!lines[i]) continue
root.missingDeps.push({ name: "OCR search", command: "omarchy pkg add tesseract tesseract-data-eng" }) var fields = lines[i].split("|")
if (fields.length === 3)
missing.push({ name: fields[1], packages: fields[2] })
} }
root.missingDeps = missing
}
function missingDependencyCommand() {
var packages = []
for (var i = 0; i < root.missingDeps.length; i++) {
var names = root.missingDeps[i].packages.split(" ")
for (var j = 0; j < names.length; j++)
if (packages.indexOf(names[j]) === -1) packages.push(names[j])
}
return packages.length ? "omarchy pkg add " + packages.join(" ") : ""
} }
function applySettings(raw) { function applySettings(raw) {
@@ -407,10 +428,9 @@ Item {
Process { Process {
id: depsProc id: depsProc
property string slot: ""
stdout: StdioCollector { stdout: StdioCollector {
waitForEnd: true waitForEnd: true
onStreamFinished: root.depResult(depsProc.slot, text) onStreamFinished: root.depResult(text)
} }
} }
Process { Process {
@@ -473,8 +493,8 @@ Item {
PanelWindow { PanelWindow {
id: panel id: panel
visible: root.opened visible: root.opened
width: root.cardWidth implicitWidth: root.cardWidth
height: root.cardHeight implicitHeight: root.cardHeight
color: "transparent" color: "transparent"
WlrLayershell.namespace: "alanfortlink-clipboard" WlrLayershell.namespace: "alanfortlink-clipboard"
WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.layer: WlrLayer.Overlay
@@ -724,7 +744,7 @@ Item {
Text { Text {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.missingDeps.length > 0 text: root.missingDeps.length > 0
? root.missingDeps[0].name + " unavailable — run: " + root.missingDeps[0].command ? root.missingDeps[0].name + " unavailable — run: " + root.missingDependencyCommand()
: "" : ""
color: Color.urgent color: Color.urgent
font.family: root.fontFamily font.family: root.fontFamily
@@ -755,9 +775,8 @@ Item {
onClicked: { onClicked: {
if (root.missingDeps.length === 0) return if (root.missingDeps.length === 0) return
root.close() root.close()
var cmd = "" var cmd = root.missingDependencyCommand()
for (var i = 0; i < root.missingDeps.length; i++) if (!cmd) return
cmd += (i ? " && " : "") + root.missingDeps[i].command
cmd += '; echo; echo "Done — press Enter to close"; read' cmd += '; echo; echo "Done — press Enter to close"; read'
Quickshell.execDetached(["omarchy-launch-terminal", "bash", "-c", cmd]) Quickshell.execDetached(["omarchy-launch-terminal", "bash", "-c", cmd])
} }
+3 -3
View File
@@ -360,7 +360,7 @@ Item {
// Decoded QR payload sits above the image so it is immediately readable. // Decoded QR payload sits above the image so it is immediately readable.
Rectangle { Rectangle {
visible: root.entry && root.entry.qr visible: !!(root.entry && root.entry.qr)
width: parent.width width: parent.width
height: qrContent.height + Style.space(12) height: qrContent.height + Style.space(12)
radius: Style.cornerRadius radius: Style.cornerRadius
@@ -456,7 +456,7 @@ Item {
// OCR text recovered from the image (searchable like any text clip). // OCR text recovered from the image (searchable like any text clip).
Rectangle { Rectangle {
id: ocrPanel id: ocrPanel
visible: root.entry && root.entry.ocr visible: !!(root.entry && root.entry.ocr)
width: parent.width width: parent.width
height: Math.min(Style.space(150), ocrContent.height + Style.space(12)) height: Math.min(Style.space(150), ocrContent.height + Style.space(12))
radius: Style.cornerRadius radius: Style.cornerRadius
@@ -599,7 +599,7 @@ Item {
} }
Text { Text {
visible: root.entry && root.entry.paths && root.entry.paths.length > 10 visible: !!(root.entry && root.entry.paths && root.entry.paths.length > 10)
text: root.entry && root.entry.paths ? "… and " + (root.entry.paths.length - 10) + " more" : "" text: root.entry && root.entry.paths ? "… and " + (root.entry.paths.length - 10) + " more" : ""
color: root.mutedFg color: root.mutedFg
font.family: root.font_ font.family: root.font_
+6 -7
View File
@@ -47,11 +47,9 @@ full theme integration.
omarchy plugin add https://github.com/alanfortlink/clipboard-history.git --enable omarchy plugin add https://github.com/alanfortlink/clipboard-history.git --enable
``` ```
Optional extras (usually already installed): No separate dependency command is required during installation. The picker
always opens; if a helper is missing, it shows the exact package command inside
```bash the window with a **Run in terminal** button.
omarchy pkg add zbar tesseract tesseract-data-eng # QR decode + OCR search
```
Already have images in history you'd like OCR'd? One-shot backfill: Already have images in history you'd like OCR'd? One-shot backfill:
@@ -63,8 +61,9 @@ That's the whole install — `omarchy plugin add` clones the repo, validates the
manifest, and enables it. It replaces the built-in `omarchy.clipboard` manifest, and enables it. It replaces the built-in `omarchy.clipboard`
(restore it later with `omarchy plugin disable alanfortlink.clipboard`). (restore it later with `omarchy plugin disable alanfortlink.clipboard`).
Omarchy's default `Super+Ctrl+V` (and `Super+Shift+V`) already routes to it Omarchy's default `Super+Ctrl+V` routes to it via the clone mechanism. An
via the clone mechanism. For a custom binding, edit the **live** config — 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 `~/.config/hypr/bindings.lua` on Quattro (a plain `bindings.conf` may exist
but is not sourced): but is not sourced):
+1 -1
View File
@@ -2,7 +2,7 @@
"schemaVersion": 1, "schemaVersion": 1,
"id": "alanfortlink.clipboard", "id": "alanfortlink.clipboard",
"name": "Clipboard History", "name": "Clipboard History",
"version": "1.0.0", "version": "1.0.1",
"author": "alanfortlink", "author": "alanfortlink",
"description": "Raycast-style clipboard history: fuzzy search over content, type, app and date, with rich per-type previews", "description": "Raycast-style clipboard history: fuzzy search over content, type, app and date, with rich per-type previews",
"kinds": [ "kinds": [