-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathutils.lua
214 lines (195 loc) · 4.93 KB
/
utils.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
local utils = {}
local modToBit = {
["ctrl"] = 1,
["control"] = 1,
["⌃"] = 1,
["shift"] = 2,
["⇧"] = 2,
["cmd"] = 4,
["command"] = 4,
["⌘"] = 4,
["alt"] = 8,
["option"] = 8,
["⌥"] = 8,
["fn"] = 16,
}
-- Converts a table of modifiers to an integer
utils.modifierFlags = function (mods)
local flags = 0
for key, value in pairs(mods) do
if value == true then
-- {["cmd"] = true, ["shift"] = true}
flags = flags | modToBit[key]
elseif type(key) == "number" then
-- {"cmd", "shift"}
flags = flags | modToBit[value]
end
end
return flags
end
local keyTopMap = {
delete = "⌫",
down = "↓",
escape = "⎋",
forwarddelete = "⌦",
help = "⍰",
home = "↖",
left = "←",
pad0 = "0︎⃣",
pad1 = "1︎⃣",
pad2 = "2︎⃣",
pad3 = "3︎⃣",
pad4 = "4︎⃣",
pad5 = "5︎⃣",
pad6 = "6︎⃣",
pad7 = "7︎⃣",
pad8 = "8︎⃣",
pad9 = "9︎⃣",
padclear = "⌧",
padenter = "⌅",
pagedown = "⇟",
pageup = "⇞",
right = "→",
tab = "⇥",
up = "↑",
}
keyTopMap["end"] = "↘"
keyTopMap["return"] = "↩"
keyTopMap["pad*"] = "*︎⃣"
keyTopMap["pad+"] = "+︎⃣"
keyTopMap["pad/"] = "/︎⃣"
keyTopMap["pad-"] = "-︎⃣"
keyTopMap["pad="] = "=︎⃣"
-- Returns a pretty representation of a key
utils.prettyKey = function (mods, key)
local flags = utils.modifierFlags(mods)
local fn, cmd, alt, ctrl, shift, k
if flags & modToBit["fn"] ~= 0 then
fn = "Fn-"
end
if flags & modToBit["cmd"] ~= 0 then
cmd = "⌘"
end
if flags & modToBit["alt"] ~= 0 then
alt = "⌥"
end
if flags & modToBit["ctrl"] ~= 0 then
ctrl = "⌃"
end
if flags & modToBit["shift"] ~= 0 then
shift = "⇧"
end
if type(key) == "string" then
k = key
else
k = hs.keycodes.map[key]
end
local function upcase(a, b)
return a .. b:upper()
end
local keytop = keyTopMap[k] or k:gsub("^(%l)", string.upper)
return table.concat({fn or "", cmd or "", alt or "", ctrl or "", shift or "", keytop})
end
-- Escapes a string for the shell
utils.shellescape = function (s)
if s == "" then
return "''"
end
return s:gsub("([^A-Za-z0-9_%-.,:/@\n])", "\\%1"):gsub("(\n)", "'\n'")
end
-- Joins a table of arguments into a command line string, escaping
-- each element for the shell
utils.shelljoin = function (...)
local args = {...}
local s = ""
for _, arg in ipairs(args) do
if s ~= "" then
s = s .. " "
end
if type(arg) == "table" then
s = s .. utils.shelljoin(table.unpack(arg))
else
s = s .. utils.shellescape(tostring(arg))
end
end
return s
end
-- Returns keys of a table
utils.keys = function (table)
local keys = {}
for key in pairs(table) do
keys[#keys + 1] = key
end
return keys
end
-- Copies all key-value pairs from one or more source tables to a target table
utils.assign = function (target, ...)
for _, source in ipairs{...} do
for key, value in pairs(source) do
target[key] = value
end
end
return target
end
-- Provides additional string functions
--
-- To use them as methods, run `knu.utils.assign(string, knu.utils.string)`.
utils.string = {
-- Tests if a string contains a substring
contains = function (str, substring)
return str:find(substring, 1, true) ~= nil
end,
-- Tests if a string starts with a prefix
startsWith = function (str, prefix)
return #prefix <= #str and str:sub(1, #prefix) == prefix
end,
-- Tests if a string ends with a suffix
endsWith = function (str, suffix)
return #suffix <= #str and str:sub(-#suffix) == suffix
end,
}
-- Wraps a function to delay its execution until after a specified time has passed since the last call
--
-- Parameters:
-- - func - The function to debounce.
-- - wait - The delay time in seconds.
-- Returns:
-- - A new debounced function.
utils.debounce = function (func, wait)
local timer = nil
return function(...)
local args = {...}
if timer then
timer:stop()
end
timer = hs.timer.doAfter(wait, function() func(table.unpack(args)) end)
end
end
-- Wraps a function to ensure it is called at most once per interval, with an optional trailing execution
--
-- Parameters:
-- - func - The function to throttle.
-- - interval - The minimum time in seconds between calls.
-- - trailing - If true, ensures the last call is executed after the interval.
-- Returns:
-- - A new throttled function.
utils.throttle = function (func, interval, trailing)
local lastCall = 0
local scheduled = false
return function(...)
local now = hs.timer.absoluteTime() / 1e9
local args = {...}
if now - lastCall >= interval then
lastCall = now
func(table.unpack(args))
elseif trailing and not scheduled then
scheduled = true
hs.timer.doAfter(interval - (now - lastCall), function()
lastCall = hs.timer.absoluteTime() / 1e9
scheduled = false
func(table.unpack(args))
end)
end
end
end
return utils