-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.lua
282 lines (255 loc) · 8.58 KB
/
util.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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
---------------------------------------------------------------------------
--
-- Utility module for away: away.util
--
-- Copyright (c) 2019-2023 shmilee
-- Licensed under GNU General Public License v2:
-- https://opensource.org/licenses/GPL-2.0
--
---------------------------------------------------------------------------
local io, os, debug, table = io, os, debug, table
local print, tostring, pairs, ipairs, rawset, pcall, require
= print, tostring, pairs, ipairs, rawset, pcall, require
local string = { format = string.format, gmatch = string.gmatch }
local awfulloaded, awful = pcall(require, "awful")
local gfsloaded, gfs = pcall(require, "gears.filesystem")
local gtabloaded, gtable = pcall(require, "gears.table")
local util = {}
util.curdir = debug.getinfo(1, 'S').source:match[[^@(.*/).*$]]
util.recursion_try_limit = 16
-- Simple Log level:
-- 10 DEBUG
-- 20 INFO
-- 30 ERROR
util.log_level = 20
util.log_std = 'stderr' -- 'stdout'
-- Print msg when level>=log_level
function util.print_msg(level, leveltxt, msg, msgprefix)
if level >= util.log_level then
if msgprefix then
msgprefix = tostring(msgprefix) .. ': '
else
msgprefix = ''
end
T = os.date('%F %H:%M:%S')
msg = T .. " Away" .. leveltxt .. ': ' .. msgprefix .. tostring(msg)
if util.log_std == 'stderr' then
io.stderr:write(msg .. '\n')
io.flush()
else
print(msg)
end
end
end
-- Print debug msg when 10>=log_level
function util.print_debug(msg, msgprefix)
util.print_msg(10, "[D]", msg, msgprefix)
end
-- Print info msg when 20>=log_level
function util.print_info(msg, msgprefix)
util.print_msg(20, "[I]", msg, msgprefix)
end
-- Print error msg when 30>=log_level
function util.print_error(msg, msgprefix)
util.print_msg(30, "[E]", debug.traceback(msg), msgprefix)
end
-- Return a sequence of numbers from head to tail by step
function util.simple_range(head, tail, step)
local res = {}
while head <= tail do
table.insert(res, head)
head = head + step
end
return res
end
-- Return first available module in the candidates
function util.find_available_module(candidates)
local c, status, module
for _, c in pairs(candidates) do
status, module = pcall(require, c)
if status then
return module
end
end
return nil
end
util.json = util.find_available_module({
'cjson', 'dkjson', 'away.third_party.dkjson',
'third_party.dkjson', 'awesome-away.third_party.dkjson',
})
util.inspect = util.find_available_module({
'inspect', 'third_party.inspect',
'away.third_party.inspect', 'awesome-away.third_party.inspect',
})
-- Return path file size in bytes
function util.get_file_size(path)
local file = io.open(path, "rb")
local size = file:seek("end")
file:close()
return size
end
-- Set Markup foreground, background color and more, like font, size, etc.
-- see https://docs.gtk.org/Pango/pango_markup.html#the-span-attributes
function util.markup_span(text, fg, bg, more)
local attrs = {}
if fg then
table.insert(attrs, string.format('foreground="%s"', fg))
end
if bg then
table.insert(attrs, string.format('background="%s"', bg))
end
more = more or {}
for i, v in pairs(more) do
table.insert(attrs, string.format('%s="%s"', i, v))
end
attrs = table.concat(attrs, ' ')
return string.format('<span %s>%s</span>', attrs, text)
end
-- Set Markup convenience Tags, like:
-- b, big, i, s, u, etc.
-- see https://docs.gtk.org/Pango/pango_markup.html#convenience-tags
function util.markup(text, tag)
return string.format('<%s>%s</%s>', tag, text, tag)
end
-- awful part
local spawn_async, spawn_async_with_shell
if awfulloaded then
spawn_async = awful.spawn.easy_async
spawn_async_with_shell = awful.spawn.easy_async_with_shell
else
-- ref: https://github.com/vicious-widgets/vicious/blob/master/spawn.lua
function spawn_async_with_shell(cmd, callback)
local out_stream = io.popen(cmd)
local stdout = out_stream:read("*all")
local success, reason, code = out_stream:close() -- requiring Lua 5.2
local stderr = 'empty stderr due to limitation of io.popen'
callback(stdout, stderr, reason, code)
return success
end
spawn_async = spawn_async_with_shell
end
-- @param spawn_async function to use
local function async_run(spawn_async, cmd, callback, pass_args)
spawn_async(cmd, function(stdout, stderr, reason, ecode)
util.print_info(
"Run command: " .. cmd .. ", DONE with exit code " .. ecode)
if type(callback) == 'function' then
if pass_args or (pass_args == nil) then
callback(stdout, stderr, reason, ecode)
else
callback()
end
end
end)
end
-- @param cmd string
-- @param callback function
-- @param pass_args boolean, default true
-- pass stdout, stderr, reason, ecode to callback if true
function util.async(cmd, callback, pass_args)
async_run(spawn_async, cmd, callback, pass_args)
end
function util.async_with_shell(cmd, callback, pass_args)
async_run(spawn_async_with_shell, cmd, callback, pass_args)
end
-- @param program string
-- @param args string Options and arguments for program
-- @param matcher string A matching string to find the instance
-- @param start string For autostart(default) or restart
-- @param callback function passed to async_with_shell after start program
function util.single_instance(program, args, matcher, start, callback)
if not program then
return nil
end
local cmd = program
if args then
cmd = cmd .. " " .. args
end
if not matcher then
matcher = cmd
end
start = start or 'autostart'
util.async_with_shell("pgrep -f -u $USER -x '" .. matcher .. "'",
function(stdout, stderr, reason, exit_code)
if exit_code == 0 then
util.print_info("[SI] '" .. matcher .. "' is running! PID=" .. stdout)
if start ~= 'autostart' then
for pid in string.gmatch(stdout, "[^\r\n]+") do
util.async_with_shell('kill ' .. pid, function(out, err, rsn, code)
if code == 0 then
util.print_info("[SI] Restart '" .. matcher .. "'!")
util.async_with_shell(cmd, callback) -- to restart
else
util.print_info('Try to kill -9 PID=' .. pid .. '! ' .. stderr)
util.async_with_shell('kill -9 ' .. pid, function(o, e, r, c)
util.print_info("[SI] Restart '" .. matcher .. "'!")
util.async_with_shell(cmd, callback) -- to restart
end)
end
end)
break -- only kill first match
end
end
else -- autostart
util.print_info("[SI] Autostart '" .. program .. "'!")
util.async_with_shell(cmd, callback)
end
end)
end
-- gfs part
if gfsloaded then
util.get_xdg_config_home = gfs.get_xdg_config_home
util.get_xdg_cache_home = gfs.get_xdg_cache_home
util.file_readable = gfs.file_readable
else
function util.get_xdg_config_home()
return (os.getenv("XDG_CONFIG_HOME")
or os.getenv("HOME") .. "/.config") .. "/"
end
function util.get_xdg_cache_home()
return (os.getenv("XDG_CACHE_HOME")
or os.getenv("HOME") .. "/.cache") .. "/"
end
function util.file_readable(filename)
local f = io.open(filename, "rb")
if f then f:close() end
return f ~= nil
end
end
-- gtable part
if gtabloaded then
util.table_crush = gtable.crush
util.table_hasitem = gtable.hasitem
util.table_merge = gtable.merge
else
-- update table *t*
function util.table_crush(t, set, raw)
if raw then
for k, v in pairs(set) do
rawset(t, k, v)
end
else
for k, v in pairs(set) do
t[k] = v
end
end
return t
end
--- Check if a table has an item and return its key.
function util.table_hasitem(t, item)
for k, v in pairs(t) do
if v == item then
return k
end
end
end
--- Merge items from one table to another one.
function util.table_merge(t, set)
for _, v in ipairs(set) do
table.insert(t, v)
end
return t
end
end
util.table_update = util.table_crush
return util