/
clipboard.lua
139 lines (118 loc) 路 3.44 KB
/
clipboard.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
-- Clipboard History
local width = 30
local maxSize = 50
local storePath = os.getenv("HOME") .. "/.clipboard"
local cachePath = storePath .. "/cache.json"
local imagePath = storePath .. "/images"
local UTI_TYPE = {
IMAGE_TIFF = "public.tiff",
IMAGE_PNG = "public.png",
PLAIN_TEXT = "public.utf8-plain-text",
}
local HISTORY_TYPE = {
IMAGE = "IMAGE",
TEXT = "TEXT",
}
function readHistoryFromCache()
hs.fs.mkdir(storePath)
local cacheFile = io.open(cachePath, "r")
if cacheFile then
local content = cacheFile:read("*a")
if content ~= "" then
return hs.json.decode(content)
end
end
return {}
end
function saveHistoryIntoCache(history)
local cacheFile = io.open(cachePath, "w")
cacheFile:write(hs.json.encode(history))
cacheFile:close()
end
function saveTemporaryImage(image)
hs.fs.mkdir(imagePath)
local imageBase64 = hs.base64.encode(image:encodeAsURLString())
local startIndex = string.len(imageBase64) / 2
local endIndex = startIndex + 5;
local filename = imagePath .. "/" .. string.sub(imageBase64, startIndex, endIndex) .. ".png"
image:saveToFile(filename)
return filename
end
function reduceHistorySize()
while #history >= maxSize do
table.remove(history, #history)
end
end
function addHistoryFromPasteboard()
local contentTypes = hs.pasteboard.contentTypes()
local item = {}
for index, uti in ipairs(contentTypes) do
if uti == UTI_TYPE.IMAGE_TIFF or uti == UTI_TYPE.IMAGE_PNG then
local image = hs.pasteboard.readImage()
item.text = "_IMAGE_"
item.type = HISTORY_TYPE.IMAGE
item.content = saveTemporaryImage(image)
break
elseif uti == UTI_TYPE.PLAIN_TEXT then
local text = hs.pasteboard.readString()
if text == nil or utf8.len(text) < 3 then
return
end
item.text = string.gsub(text, "[\r\n]+", " ")
item.type = HISTORY_TYPE.TEXT;
item.content = text;
break
end
end
if item.text then
for index, el in ipairs(history) do
if item.content == el.content then
table.remove(history, index)
end
end
local appname = hs.window.focusedWindow():application():name()
item.subText = appname .. " / " .. os.date("%Y-%m-%d %H:%M", os.time())
table.insert(history, 1, item)
saveHistoryIntoCache(history)
end
end
function showClipboard()
local choices = hs.fnutils.map(history, function(item)
local choice = hs.fnutils.copy(item)
choice.text = " " .. choice.text
choice.subText = " " .. choice.subText
if choice.type == HISTORY_TYPE.IMAGE then
choice.image = hs.image.imageFromPath(item.content)
end
return choice
end)
chooser:width(width);
chooser:choices(choices);
chooser:show()
end
function choiceClipboard(choice)
if choice then
if choice.type == HISTORY_TYPE.IMAGE then
local image = hs.image.imageFromPath(choice.content)
hs.pasteboard.writeObjects(image)
else
hs.pasteboard.setContents(choice.content)
end
hs.eventtap.keyStroke({ "cmd" }, "v")
end
if chooser:query() ~= "" then
chooser:query("")
end
end
history = readHistoryFromCache()
chooser = hs.chooser.new(choiceClipboard)
preChangeCount = hs.pasteboard.changeCount()
watcher = hs.timer.new(0.5, function()
local changeCount = hs.pasteboard.changeCount()
if changeCount ~= preChangeCount then
pcall(addHistoryFromPasteboard)
preChangeCount = changeCount
end
end)
watcher:start()
hs.hotkey.bind({ "cmd", "shift" }, "v", showClipboard)