--- ==== Seal.plugins.pasteboard ==== --- --- Visual, searchable pasteboard (ie clipboard) history local obj = {} obj.__index = obj obj.__name = "seal_pasteboard" obj.timer = nil obj.lastItem = nil obj.itemBuffer = {} obj.choices = {} --- Seal.plugins.pasteboard.historySize --- Variable --- --- The number of history items to keep. Defaults to 50 obj.historySize = 50 --- Seal.plugins.pasteboard.saveHistory --- Variable --- --- 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 } } end function obj:bare() return nil end function obj.choicesPasteboardCommand(query) -- 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 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 end if item["dateTime"] then choice["subText"] = choice["subText"] .. " :: " .. item["dateTime"] end return choice end function obj.completionCallback(rowInfo) if rowInfo["type"] == "copy" then hs.pasteboard.setContents(rowInfo["name"]) end end function obj.checkPasteboard() local pasteboard = hs.pasteboard.getContents() local shouldSave = false if pasteboard == nil then return end if (#obj.itemBuffer == 0) or (pasteboard ~= obj.itemBuffer[#obj.itemBuffer]["text"]) then local currentTypes = hs.pasteboard.allContentTypes()[1] if currentTypes == nil then print("ERROR: NO PASTEBOARD CURRENT TYPES. Please file a bug so we can understand this:") print(hs.inspect(pasteboard)) return end for _, aType in pairs(currentTypes) do for _, uti in pairs(obj.skipUTIs) do if uti == aType then return end end end 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 if shouldSave then obj.save() end end function obj.save() local json = hs.json.encode(obj.itemBuffer) 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") 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 end obj.load() if obj.timer == nil then obj.timer = hs.timer.doEvery(1, function() obj.checkPasteboard(obj) end) obj.timer:start() end return obj