Skip to content

Commit

Permalink
Dramatically improve efficiency of Seal pasteboard plugin (#330)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmsj authored Feb 27, 2025
1 parent da4cb1e commit 78a0f0e
Showing 1 changed file with 77 additions and 47 deletions.
124 changes: 77 additions & 47 deletions Source/Seal.spoon/seal_pasteboard.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ obj.__name = "seal_pasteboard"
obj.timer = nil
obj.lastItem = nil
obj.itemBuffer = {}
obj.choices = {}

--- Seal.plugins.pasteboard.historySize
--- Variable
Expand All @@ -20,13 +21,39 @@ obj.historySize = 50
--- A boolean, true if Seal should automatically load/save clipboard history. Defaults to true
obj.saveHistory = true

--- Seal.plugins.pasteboard.skipUTIs
--- Variable
---
--- An array of UTIs to skip when saving to the history. Defaults to:
--- ```
--- {
--- "de.petermaurer.TransientPasteboardType",
--- "com.typeit4me.clipping",
--- "Pasteboard generator type",
--- "com.agilebits.onepassword",
--- "org.nspasteboard.TransientType",
--- "org.nspasteboard.ConcealedType",
--- "org.nspasteboard.AutoGeneratedType"
--- }
--- ```
obj.skipUTIs = {
"de.petermaurer.TransientPasteboardType",
"com.typeit4me.clipping",
"Pasteboard generator type",
"com.agilebits.onepassword",
"org.nspasteboard.TransientType",
"org.nspasteboard.ConcealedType",
"org.nspasteboard.AutoGeneratedType"
}

function obj:commands()
return {pb = {
cmd = "pb",
fn = obj.choicesPasteboardCommand,
name = "Pasteboard",
description = "Pasteboard history",
plugin = obj.__name
return {
pb = {
cmd = "pb",
fn = obj.choicesPasteboardCommand,
name = "Pasteboard",
description = "Pasteboard history",
plugin = obj.__name
}
}
end
Expand All @@ -36,40 +63,38 @@ function obj:bare()
end

function obj.choicesPasteboardCommand(query)
local choices = {}

for i = #obj.itemBuffer, 1, -1 do
local pasteboardItem = obj.itemBuffer[i]
local choice = {}

if not string.find(string.lower(pasteboardItem["text"]), string.lower(query)) then
goto continue
end
-- Return the choices that match the query
return hs.fnutils.filter(obj.choices, function(choice)
return string.find(string.lower(choice["text"]), string.lower(query))
end)
end

choice["name"] = pasteboardItem["text"]
choice["text"] = pasteboardItem["text"]
choice["kind"] = kind
choice["plugin"] = obj.__name
choice["type"] = "copy"
choice["subText"] = ""
if pasteboardItem["uti"] then
choice["subText"] = pasteboardItem["uti"]
if hs.application.defaultAppForUTI then
local bundleID = hs.application.defaultAppForUTI(pasteboardItem["uti"])
print("Default app for "..pasteboardItem["uti"].." :: "..(bundleID or "(null)"))
if bundleID then
choice["image"] = hs.image.imageFromAppBundle(bundleID)
end
function obj.pasteboardToChoice(item)
local choice = {}

choice["uuid"] = item["uuid"]
choice["name"] = item["text"]
choice["text"] = item["text"]
choice["kind"] = kind
choice["plugin"] = obj.__name
choice["type"] = "copy"
choice["subText"] = ""

if item["uti"] then
choice["subText"] = item["uti"]
if hs.application.defaultAppForUTI then
local bundleID = hs.application.defaultAppForUTI(item["uti"])
print("Default app for " .. item["uti"] .. " :: " .. (bundleID or "(null)"))
if bundleID then
choice["image"] = hs.image.imageFromAppBundle(bundleID)
end
end
if pasteboardItem["dateTime"] then
choice["subText"] = choice["subText"] .. " :: " .. pasteboardItem["dateTime"]
end
table.insert(choices, choice)

::continue::
end
return choices
if item["dateTime"] then
choice["subText"] = choice["subText"] .. " :: " .. item["dateTime"]
end

return choice
end

function obj.completionCallback(rowInfo)
Expand All @@ -93,28 +118,28 @@ function obj.checkPasteboard()
print(hs.inspect(pasteboard))
return
end
for _,aType in pairs(currentTypes) do
for _,uti in pairs({"de.petermaurer.TransientPasteboardType",
"com.typeit4me.clipping",
"Pasteboard generator type",
"com.agilebits.onepassword",
"org.nspasteboard.TransientType",
"org.nspasteboard.ConcealedType",
"org.nspasteboard.AutoGeneratedType"}) do
for _, aType in pairs(currentTypes) do
for _, uti in pairs(obj.skipUTIs) do
if uti == aType then
return
end
end
end
item = {}
local item = {}
item["uuid"] = hs.host.uuid()
item["text"] = pasteboard
item["uti"] = currentTypes[1]
item["dateTime"] = os.date()

table.insert(obj.itemBuffer, item)
table.insert(obj.choices, obj.pasteboardToChoice(item))

shouldSave = true
end
if #obj.itemBuffer > obj.historySize then
table.remove(obj.itemBuffer, 1)
table.remove(obj.choices, 1)

shouldSave = true
end

Expand All @@ -125,19 +150,24 @@ end

function obj.save()
local json = hs.json.encode(obj.itemBuffer)
local file = io.open(os.getenv("HOME").."/.hammerspoon/pasteboard_history.json", "w")
local file = io.open(os.getenv("HOME") .. "/.hammerspoon/pasteboard_history.json", "w")
if file then
file:write(json)
file:close()
end
end

function obj.load()
local file = io.open(os.getenv("HOME").."/.hammerspoon/pasteboard_history.json", "r")
local file = io.open(os.getenv("HOME") .. "/.hammerspoon/pasteboard_history.json", "r")
if file then
local json = hs.json.decode(file:read())
if json then
obj.itemBuffer = json

-- Convert all the items to the choice buffer
for _, v in ipairs(obj.itemBuffer) do
table.insert(obj.choices, obj.pasteboardToChoice(v))
end
end
file:close()
end
Expand Down

0 comments on commit 78a0f0e

Please sign in to comment.