awful.tag: fix screen in viewonly
[awesome.git] / lib / awful / util.lua.in
blob3c113978429f63dba1c44e393821060b8a8411fd
1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2008 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 -- Grab environment we need
8 local os = os
9 local io = io
10 local assert = assert
11 local loadstring = loadstring
12 local loadfile = loadfile
13 local debug = debug
14 local pairs = pairs
15 local ipairs = ipairs
16 local type = type
17 local rtable = table
18 local pairs = pairs
19 local string = string
20 local capi =
22 awesome = awesome,
23 mouse = mouse
26 --- Utility module for awful
27 module("awful.util")
29 table = {}
31 shell = os.getenv("SHELL") or "/bin/sh"
33 function deprecate(see)
34 io.stderr:write("W: awful: function is deprecated")
35 if see then
36 io.stderr:write(", see " .. see)
37 end
38 io.stderr:write("\n")
39 io.stderr:write(debug.traceback())
40 end
42 --- Strip alpha part of color.
43 -- @param color The color.
44 -- @return The color without alpha channel.
45 function color_strip_alpha(color)
46 if color:len() == 9 then
47 color = color:sub(1, 7)
48 end
49 return color
50 end
52 --- Make i cycle.
53 -- @param t A length.
54 -- @param i An absolute index to fit into #t.
55 -- @return The object at new index.
56 function cycle(t, i)
57 while i > t do i = i - t end
58 while i < 1 do i = i + t end
59 return i
60 end
62 --- Create a directory
63 -- @param dir The directory.
64 -- @return mkdir return code
65 function mkdir(dir)
66 return os.execute("mkdir -p " .. dir)
67 end
69 --- Spawn a program.
70 -- @param cmd The command.
71 -- @param sn Enable startup-notification.
72 -- @param screen The screen where to spawn window.
73 -- @return The awesome.spawn return value.
74 function spawn(cmd, sn, screen)
75 if cmd and cmd ~= "" then
76 if sn == nil then sn = true end
77 return capi.awesome.spawn(cmd, sn, screen or capi.mouse.screen)
78 end
79 end
81 --- Spawn a program using the shell.
82 -- @param cmd The command.
83 -- @param screen The screen where to run the command.
84 function spawn_with_shell(cmd, screen)
85 if cmd and cmd ~= "" then
86 cmd = shell .. " -c \"" .. cmd .. "\""
87 return capi.awesome.spawn(cmd, false, screen or capi.mouse.screen)
88 end
89 end
91 --- Read a program output and returns its output as a string.
92 -- @param cmd The command to run.
93 -- @return A string with the program output, or the error if one occured.
94 function pread(cmd)
95 if cmd and cmd ~= "" then
96 local f, err = io.popen(cmd, 'r')
97 if f then
98 local s = f:read("*all")
99 f:close()
100 return s
101 else
102 return err
107 --- Eval Lua code.
108 -- @return The return value of Lua code.
109 function eval(s)
110 return assert(loadstring(s))()
113 local xml_entity_names = { ["'"] = "&apos;", ["\""] = "&quot;", ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;" };
114 --- Escape a string from XML char.
115 -- Useful to set raw text in textbox.
116 -- @param text Text to escape.
117 -- @return Escape text.
118 function escape(text)
119 return text and text:gsub("['&<>\"]", xml_entity_names) or nil
122 local xml_entity_chars = { lt = "<", gt = ">", nbsp = " ", quot = "\"", apos = "'", ndash = "-", mdash = "-", amp = "&" };
123 --- Unescape a string from entities.
124 -- @param text Text to unescape.
125 -- @return Unescaped text.
126 function unescape(text)
127 return text and text:gsub("&(%a+);", xml_entity_chars) or nil
130 --- Check if a file is a Lua valid file.
131 -- This is done by loading the content and compiling it with loadfile().
132 -- @param path The file path.
133 -- @return A function if everything is alright, a string with the error
134 -- otherwise.
135 function checkfile(path)
136 local f, e = loadfile(path)
137 -- Return function if function, otherwise return error.
138 if f then return f end
139 return e
142 --- Try to restart awesome.
143 -- It checks if the configuration file is valid, and then restart if it's ok.
144 -- If it's not ok, the error will be returned.
145 -- @return Never return if awesome restart, or return a string error.
146 function restart()
147 local c = checkfile(capi.awesome.conffile)
149 if type(c) ~= "function" then
150 return c
153 capi.awesome.restart()
156 --- Get the user's config or cache dir.
157 -- It first checks XDG_CONFIG_HOME / XDG_CACHE_HOME, but then goes with the
158 -- default paths.
159 -- @param d The directory to get (either "config" or "cache").
160 -- @return A string containing the requested path.
161 function getdir(d)
162 if d == "config" then
163 local dir = os.getenv("XDG_CONFIG_HOME")
164 if dir then
165 return dir .. "/awesome"
167 return os.getenv("HOME") .. "/.config/awesome"
168 elseif d == "cache" then
169 local dir = os.getenv("XDG_CACHE_HOME")
170 if dir then
171 return dir .. "/awesome"
173 return os.getenv("HOME").."/.cache/awesome"
177 --- Check if file exists and is readable.
178 -- @param filename The file path
179 -- @return True if file exists and readable.
180 function file_readable(filename)
181 local file = io.open(filename)
182 if file then
183 io.close(file)
184 return true
186 return false
189 local function subset_mask_apply(mask, set)
190 local ret = {}
191 for i = 1, #set do
192 if mask[i] then
193 rtable.insert(ret, set[i])
196 return ret
199 local function subset_next(mask)
200 local i = 1
201 while i <= #mask and mask[i] do
202 mask[i] = false
203 i = i + 1
206 if i <= #mask then
207 mask[i] = 1
208 return true
210 return false
213 --- Return all subsets of a specific set.
214 -- This function, giving a set, will return all subset it.
215 -- For example, if we consider a set with value { 10, 15, 34 },
216 -- it will return a table containing 2^n set:
217 -- { }, { 10 }, { 15 }, { 34 }, { 10, 15 }, { 10, 34 }, etc.
218 -- @param set A set.
219 -- @return A table with all subset.
220 function subsets(set)
221 local mask = {}
222 local ret = {}
223 for i = 1, #set do mask[i] = false end
225 -- Insert the empty one
226 rtable.insert(ret, {})
228 while subset_next(mask) do
229 rtable.insert(ret, subset_mask_apply(mask, set))
231 return ret
234 --- Join all tables given as parameters.
235 -- This will iterate all tables and insert all their keys into a new table.
236 -- @param args A list of tables to join
237 -- @return A new table containing all keys from the arguments.
238 function table.join(...)
239 local ret = {}
240 for i = 1, arg.n do
241 if arg[i] then
242 for k, v in pairs(arg[i]) do
243 if type(k) == "number" then
244 rtable.insert(ret, v)
245 else
246 ret[k] = v
251 return ret
254 --- Check if a table has an item and return its key.
255 -- @param t The table.
256 -- @param item The item to look for in values of the table.
257 -- @return The key were the item is found, or nil if not found.
258 function table.hasitem(t, item)
259 for k, v in pairs(t) do
260 if v == item then
261 return k
266 --- Split a string into multiple lines
267 -- @param text String to wrap.
268 -- @param width Maximum length of each line. Default: 72.
269 -- @param indent Number of spaces added before each wrapped line. Default: 0.
270 -- @return The string with lines wrapped to width.
271 function linewrap(text, width, indent)
272 local text = text or ""
273 local width = width or 72
274 local indent = indent or 0
276 local pos = 1
277 return text:gsub("(%s+)()(%S+)()",
278 function(sp, st, word, fi)
279 if fi - pos > width then
280 pos = st
281 return "\n" .. string.rep(" ", indent) .. word
283 end)
286 --- Get a sorted table with all integer keys from a table
287 -- @param t the table for which the keys to get
288 -- @return A table with keys
289 function table.keys(t)
290 local keys = { }
291 for k, _ in pairs(t) do
292 rtable.insert(keys, k)
294 rtable.sort(keys, function (a, b)
295 return type(a) == type(b) and a < b or false
296 end)
297 return keys
300 --- Filter a tables keys for certain content types
301 -- @param t The table to retrieve the keys for
302 -- @param ... the types to look for
303 -- @return A filtered table with keys
304 function table.keys_filter(t, ...)
305 local keys = table.keys(t)
306 local keys_filtered = { }
307 for _, k in pairs(keys) do
308 for _, et in pairs(arg) do
309 if type(t[k]) == et then
310 rtable.insert(keys_filtered, k)
311 break
315 return keys_filtered
318 --- Reverse a table
319 -- @param t the table to reverse
320 -- @return the reversed table
321 function table.reverse(t)
322 local tr = { }
323 -- reverse all elements with integer keys
324 for _, v in ipairs(t) do
325 rtable.insert(tr, 1, v)
327 -- add the remaining elements
328 for k, v in pairs(t) do
329 if type(v) ~= "number" then
330 tr[k] = v
333 return tr
336 --- Clone a table
337 -- @param t the table to clone
338 -- @return a clone of t
339 function table.clone(t)
340 local c = { }
341 for k, v in pairs(t) do
342 c[k] = v
344 return c
347 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80