Add shell plugin model tests

This commit is contained in:
David Heinemeier Hansson
2026-05-25 14:18:39 +02:00
parent 4277f5346b
commit 829c1fa4f7
61 changed files with 3236 additions and 1168 deletions
+17 -68
View File
@@ -3,6 +3,7 @@ import Quickshell.Io
import Quickshell.Wayland
import QtQuick
import qs.Commons
import "ClipboardHistory.js" as ClipboardHistory
Item {
id: root
@@ -55,48 +56,15 @@ Item {
}
function normalizeEntry(value) {
if (typeof value === "string") {
return value.length > 0 ? { type: "text", text: value } : null
}
if (!value || typeof value !== "object") return null
var type = String(value.type || value.kind || "")
if (type === "text") {
var text = String(value.text || "")
return text.length > 0 ? { type: "text", text: text } : null
}
if (type === "image") {
var path = String(value.path || "")
if (!path) return null
return {
type: "image",
path: path,
mime: String(value.mime || "image/png")
}
}
return null
return ClipboardHistory.normalizeEntry(value)
}
function entryKey(entry) {
if (!entry) return ""
if (entry.type === "image") return "image:" + String(entry.path || "")
return "text:" + String(entry.text || "")
return ClipboardHistory.entryKey(entry)
}
function loadHistory(raw) {
try {
var parsed = JSON.parse(String(raw || "[]"))
var next = []
if (Array.isArray(parsed)) {
for (var i = 0; i < parsed.length; i++) {
var entry = root.normalizeEntry(parsed[i])
if (entry) next.push(entry)
}
}
root.history = next
} catch (e) {
root.history = []
}
root.history = ClipboardHistory.parseHistory(raw)
if (root.opened) root.rebuildDisplay()
}
@@ -105,52 +73,33 @@ Item {
}
function addClipboardEntry(entry) {
var normalized = root.normalizeEntry(entry)
var normalized = ClipboardHistory.normalizeEntry(entry)
if (!normalized) return
var key = root.entryKey(normalized)
var next = [normalized]
for (var i = 0; i < root.history.length && next.length < 100; i++) {
var existing = root.normalizeEntry(root.history[i])
if (!existing || root.entryKey(existing) === key) continue
next.push(existing)
}
root.history = next
root.history = ClipboardHistory.addEntry(root.history, normalized, 100)
root.saveHistory()
if (root.opened) root.rebuildDisplay()
}
function addClipboardJson(line) {
var raw = String(line || "").trim()
if (!raw) return
try { root.addClipboardEntry(JSON.parse(raw)) } catch (e) {}
root.addClipboardEntry(ClipboardHistory.parseEntryJson(line))
}
function rebuildDisplay() {
var query = root.filterText.trim().toLowerCase()
var rows = ClipboardHistory.displayRows(root.history, root.filterText, 50)
displayModel.clear()
var outCount = 0
for (var i = 0; i < root.history.length; i++) {
var entry = root.normalizeEntry(root.history[i])
if (!entry) continue
var isImage = entry.type === "image"
var searchable = isImage ? ("image " + String(entry.mime || "")) : String(entry.text || "")
if (query && searchable.toLowerCase().indexOf(query) < 0) continue
for (var i = 0; i < rows.length; i++) {
var row = rows[i]
displayModel.append({
entryType: entry.type,
fullText: isImage ? "" : String(entry.text || ""),
previewText: isImage ? "Image" : String(entry.text || "").replace(/\s+/g, " "),
previewImage: isImage ? Util.fileUrl(entry.path) : "",
path: isImage ? String(entry.path || "") : "",
mime: isImage ? String(entry.mime || "image/png") : "text/plain",
index: outCount
entryType: row.entryType,
fullText: row.fullText,
previewText: row.previewText,
previewImage: row.previewImage ? Util.fileUrl(row.previewImage) : "",
path: row.path,
mime: row.mime,
index: row.index
})
outCount++
if (outCount >= 50) break
}
if (displayModel.count === 0) selectedIndex = 0
+129
View File
@@ -0,0 +1,129 @@
function normalizeEntry(value) {
if (typeof value === "string")
return value.length > 0 ? { type: "text", text: value } : null
if (!value || typeof value !== "object") return null
var type = String(value.type || value.kind || "")
if (type === "text") {
var text = String(value.text || "")
return text.length > 0 ? { type: "text", text: text } : null
}
if (type === "image") {
var path = String(value.path || "")
if (!path) return null
return {
type: "image",
path: path,
mime: String(value.mime || "image/png")
}
}
return null
}
function entryKey(entry) {
if (!entry) return ""
if (entry.type === "image") return "image:" + String(entry.path || "")
return "text:" + String(entry.text || "")
}
function parseHistory(raw) {
try {
var parsed = JSON.parse(String(raw || "[]"))
var next = []
if (!Array.isArray(parsed)) return next
for (var i = 0; i < parsed.length; i++) {
var entry = normalizeEntry(parsed[i])
if (entry) next.push(entry)
}
return next
} catch (e) {
return []
}
}
function addEntry(history, entry, limit) {
var normalized = normalizeEntry(entry)
var max = limit === undefined || limit === null ? 100 : Number(limit)
if (isNaN(max)) max = 100
max = Math.max(0, max)
if (!normalized) return Array.isArray(history) ? history.slice(0, max) : []
if (max === 0) return []
var key = entryKey(normalized)
var next = [normalized]
var values = Array.isArray(history) ? history : []
for (var i = 0; i < values.length && next.length < max; i++) {
var existing = normalizeEntry(values[i])
if (!existing || entryKey(existing) === key) continue
next.push(existing)
}
return next
}
function parseEntryJson(line) {
var raw = String(line || "").trim()
if (!raw) return null
try { return normalizeEntry(JSON.parse(raw)) } catch (e) { return null }
}
function searchableText(entry) {
if (!entry) return ""
if (entry.type === "image") return "image " + String(entry.mime || "")
return String(entry.text || "")
}
function previewText(entry) {
if (!entry) return ""
if (entry.type === "image") return "Image"
return String(entry.text || "").replace(/\s+/g, " ")
}
function displayRows(history, query, limit) {
var values = Array.isArray(history) ? history : []
var needle = String(query || "").trim().toLowerCase()
var max = limit === undefined || limit === null ? 50 : Number(limit)
if (isNaN(max)) max = 50
max = Math.max(0, max)
if (max === 0) return []
var rows = []
for (var i = 0; i < values.length; i++) {
var entry = normalizeEntry(values[i])
if (!entry) continue
if (needle && searchableText(entry).toLowerCase().indexOf(needle) < 0) continue
var isImage = entry.type === "image"
rows.push({
entryType: entry.type,
fullText: isImage ? "" : String(entry.text || ""),
previewText: previewText(entry),
previewImage: isImage ? String(entry.path || "") : "",
path: isImage ? String(entry.path || "") : "",
mime: isImage ? String(entry.mime || "image/png") : "text/plain",
index: rows.length
})
if (rows.length >= max) break
}
return rows
}
if (typeof module !== "undefined") {
module.exports = {
normalizeEntry: normalizeEntry,
entryKey: entryKey,
parseHistory: parseHistory,
addEntry: addEntry,
parseEntryJson: parseEntryJson,
searchableText: searchableText,
previewText: previewText,
displayRows: displayRows
}
}