104 lines
2.7 KiB
QML
104 lines
2.7 KiB
QML
import QtQuick
|
||
import Quickshell
|
||
import qs.Commons
|
||
import qs.Services
|
||
|
||
QtObject {
|
||
id: clipboardHistory
|
||
|
||
function parseImageMeta(preview) {
|
||
const re = /\[\[\s*binary data\s+([\d\.]+\s*(?:KiB|MiB|GiB|B))\s+(\w+)\s+(\d+)x(\d+)\s*\]\]/i
|
||
const m = (preview || "").match(re)
|
||
if (!m) return null
|
||
return { size: m[1], fmt: (m[2] || "").toUpperCase(), w: Number(m[3]), h: Number(m[4]) }
|
||
}
|
||
|
||
function formatTextPreview(preview) {
|
||
const normalized = (preview || "").replace(/\s+/g, ' ').trim()
|
||
const lines = normalized.split(/\n+/)
|
||
const title = (lines[0] || "Text").slice(0, 60)
|
||
let subtitle = ""
|
||
if (lines.length > 1) {
|
||
subtitle = lines[1].slice(0, 80)
|
||
} else {
|
||
subtitle = `${normalized.length} chars`
|
||
}
|
||
return { title, subtitle }
|
||
}
|
||
|
||
function createClipboardEntry(item) {
|
||
if (item.isImage) {
|
||
const meta = parseImageMeta(item.preview)
|
||
const title = meta ? `Image ${meta.w}×${meta.h}` : "Image"
|
||
const subtitle = meta ? `${meta.size} · ${meta.fmt}` : (item.preview || "")
|
||
return {
|
||
"isClipboard": true,
|
||
"name": title,
|
||
"content": subtitle,
|
||
"icon": "image",
|
||
"type": 'image',
|
||
"id": item.id,
|
||
"mime": item.mime
|
||
}
|
||
} else {
|
||
const parts = formatTextPreview(item.preview)
|
||
return {
|
||
"isClipboard": true,
|
||
"name": parts.title,
|
||
"content": parts.subtitle,
|
||
"icon": "content_paste",
|
||
"type": 'text',
|
||
"id": item.id
|
||
}
|
||
}
|
||
}
|
||
|
||
function createEmptyEntry() {
|
||
return {
|
||
"isClipboard": true,
|
||
"name": "No clipboard history",
|
||
"content": "No matching clipboard entries found",
|
||
"icon": "content_paste_off",
|
||
"execute": function () {}
|
||
}
|
||
}
|
||
|
||
function processQuery(query, items) {
|
||
const results = []
|
||
if (!query.startsWith(">clip")) {
|
||
return results
|
||
}
|
||
|
||
const searchTerm = query.slice(5).trim().toLowerCase()
|
||
|
||
// Dependency hook without side effects
|
||
const _rev = CliphistService.revision
|
||
const source = items || CliphistService.items
|
||
|
||
source.forEach(function (item) {
|
||
const hay = (item.preview || "").toLowerCase()
|
||
if (!searchTerm || hay.indexOf(searchTerm) !== -1) {
|
||
const entry = createClipboardEntry(item)
|
||
// Attach execute at this level to avoid duplicating functions
|
||
entry.execute = function () {
|
||
CliphistService.copyToClipboard(item.id)
|
||
}
|
||
results.push(entry)
|
||
}
|
||
})
|
||
|
||
if (results.length === 0) {
|
||
results.push(createEmptyEntry())
|
||
}
|
||
|
||
return results
|
||
}
|
||
|
||
function refresh() {
|
||
CliphistService.list(100)
|
||
}
|
||
|
||
function clearAll() {
|
||
CliphistService.wipeAll()
|
||
}
|
||
}
|