Remove "encoding=utf-8" from Vim modelines
[awesome.git] / lib / awful / util.lua.in
blob56ddbfa737d808c13634d0c6cd840f21597e890b
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. Must be greater than zero.
54 -- @param i An absolute index to fit into #t.
55 -- @return An integer in (1, t) or nil if t is less than or equal to zero.
56 function cycle(t, i)
57 if t < 1 then return end
58 while i > t do i = i - t end
59 while i < 1 do i = i + t end
60 return i
61 end
63 --- Create a directory
64 -- @param dir The directory.
65 -- @return mkdir return code
66 function mkdir(dir)
67 return os.execute("mkdir -p " .. dir)
68 end
70 --- Spawn a program.
71 -- @param cmd The command.
72 -- @param sn Enable startup-notification.
73 -- @param screen The screen where to spawn window.
74 -- @return The awesome.spawn return value.
75 function spawn(cmd, sn, screen)
76 if cmd and cmd ~= "" then
77 if sn == nil then sn = true end
78 return capi.awesome.spawn(cmd, sn, screen or capi.mouse.screen)
79 end
80 end
82 --- Spawn a program using the shell.
83 -- @param cmd The command.
84 -- @param screen The screen where to run the command.
85 function spawn_with_shell(cmd, screen)
86 if cmd and cmd ~= "" then
87 cmd = shell .. " -c \"" .. cmd .. "\""
88 return capi.awesome.spawn(cmd, false, screen or capi.mouse.screen)
89 end
90 end
92 --- Read a program output and returns its output as a string.
93 -- @param cmd The command to run.
94 -- @return A string with the program output, or the error if one occured.
95 function pread(cmd)
96 if cmd and cmd ~= "" then
97 local f, err = io.popen(cmd, 'r')
98 if f then
99 local s = f:read("*all")
100 f:close()
101 return s
102 else
103 return err
108 --- Eval Lua code.
109 -- @return The return value of Lua code.
110 function eval(s)
111 return assert(loadstring(s))()
114 local xml_entity_names = { ["'"] = "&apos;", ["\""] = "&quot;", ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;" };
115 --- Escape a string from XML char.
116 -- Useful to set raw text in textbox.
117 -- @param text Text to escape.
118 -- @return Escape text.
119 function escape(text)
120 return text and text:gsub("['&<>\"]", xml_entity_names) or nil
123 local xml_entity_chars = { lt = "<", gt = ">", nbsp = " ", quot = "\"", apos = "'", ndash = "-", mdash = "-", amp = "&" };
124 --- Unescape a string from entities.
125 -- @param text Text to unescape.
126 -- @return Unescaped text.
127 function unescape(text)
128 return text and text:gsub("&(%a+);", xml_entity_chars) or nil
131 --- Check if a file is a Lua valid file.
132 -- This is done by loading the content and compiling it with loadfile().
133 -- @param path The file path.
134 -- @return A function if everything is alright, a string with the error
135 -- otherwise.
136 function checkfile(path)
137 local f, e = loadfile(path)
138 -- Return function if function, otherwise return error.
139 if f then return f end
140 return e
143 --- Try to restart awesome.
144 -- It checks if the configuration file is valid, and then restart if it's ok.
145 -- If it's not ok, the error will be returned.
146 -- @return Never return if awesome restart, or return a string error.
147 function restart()
148 local c = checkfile(capi.awesome.conffile)
150 if type(c) ~= "function" then
151 return c
154 capi.awesome.restart()
157 --- Get the user's config or cache dir.
158 -- It first checks XDG_CONFIG_HOME / XDG_CACHE_HOME, but then goes with the
159 -- default paths.
160 -- @param d The directory to get (either "config" or "cache").
161 -- @return A string containing the requested path.
162 function getdir(d)
163 if d == "config" then
164 local dir = os.getenv("XDG_CONFIG_HOME")
165 if dir then
166 return dir .. "/awesome"
168 return os.getenv("HOME") .. "/.config/awesome"
169 elseif d == "cache" then
170 local dir = os.getenv("XDG_CACHE_HOME")
171 if dir then
172 return dir .. "/awesome"
174 return os.getenv("HOME").."/.cache/awesome"
178 --- Search for an icon and return the full path.
179 -- It searches for the icon path under the directories given w/the right ext
180 -- @param iconname The name of the icon to search for.
181 -- @param exts Table of image extensions allowed, otherwise { 'png', gif' }
182 -- @param dirs Table of dirs to search, otherwise { '/usr/share/pixmaps/' }
183 function geticonpath(iconname, exts, dirs)
184 exts = exts or { 'png', 'gif' }
185 dirs = dirs or { '/usr/share/pixmaps/' }
186 for _, d in pairs(dirs) do
187 for _, e in pairs(exts) do
188 local icon = d .. iconname .. '.' .. e
189 if file_readable(icon) then
190 return icon
191 end
192 end
193 end
196 --- Check if file exists and is readable.
197 -- @param filename The file path
198 -- @return True if file exists and readable.
199 function file_readable(filename)
200 local file = io.open(filename)
201 if file then
202 io.close(file)
203 return true
205 return false
208 local function subset_mask_apply(mask, set)
209 local ret = {}
210 for i = 1, #set do
211 if mask[i] then
212 rtable.insert(ret, set[i])
215 return ret
218 local function subset_next(mask)
219 local i = 1
220 while i <= #mask and mask[i] do
221 mask[i] = false
222 i = i + 1
225 if i <= #mask then
226 mask[i] = 1
227 return true
229 return false
232 --- Return all subsets of a specific set.
233 -- This function, giving a set, will return all subset it.
234 -- For example, if we consider a set with value { 10, 15, 34 },
235 -- it will return a table containing 2^n set:
236 -- { }, { 10 }, { 15 }, { 34 }, { 10, 15 }, { 10, 34 }, etc.
237 -- @param set A set.
238 -- @return A table with all subset.
239 function subsets(set)
240 local mask = {}
241 local ret = {}
242 for i = 1, #set do mask[i] = false end
244 -- Insert the empty one
245 rtable.insert(ret, {})
247 while subset_next(mask) do
248 rtable.insert(ret, subset_mask_apply(mask, set))
250 return ret
253 --- Join all tables given as parameters.
254 -- This will iterate all tables and insert all their keys into a new table.
255 -- @param args A list of tables to join
256 -- @return A new table containing all keys from the arguments.
257 function table.join(...)
258 local ret = {}
259 for i, t in ipairs({...}) do
260 if t then
261 for k, v in pairs(t) do
262 if type(k) == "number" then
263 rtable.insert(ret, v)
264 else
265 ret[k] = v
270 return ret
273 --- Check if a table has an item and return its key.
274 -- @param t The table.
275 -- @param item The item to look for in values of the table.
276 -- @return The key were the item is found, or nil if not found.
277 function table.hasitem(t, item)
278 for k, v in pairs(t) do
279 if v == item then
280 return k
285 --- Split a string into multiple lines
286 -- @param text String to wrap.
287 -- @param width Maximum length of each line. Default: 72.
288 -- @param indent Number of spaces added before each wrapped line. Default: 0.
289 -- @return The string with lines wrapped to width.
290 function linewrap(text, width, indent)
291 local text = text or ""
292 local width = width or 72
293 local indent = indent or 0
295 local pos = 1
296 return text:gsub("(%s+)()(%S+)()",
297 function(sp, st, word, fi)
298 if fi - pos > width then
299 pos = st
300 return "\n" .. string.rep(" ", indent) .. word
302 end)
305 --- Get a sorted table with all integer keys from a table
306 -- @param t the table for which the keys to get
307 -- @return A table with keys
308 function table.keys(t)
309 local keys = { }
310 for k, _ in pairs(t) do
311 rtable.insert(keys, k)
313 rtable.sort(keys, function (a, b)
314 return type(a) == type(b) and a < b or false
315 end)
316 return keys
319 --- Filter a tables keys for certain content types
320 -- @param t The table to retrieve the keys for
321 -- @param ... the types to look for
322 -- @return A filtered table with keys
323 function table.keys_filter(t, ...)
324 local keys = table.keys(t)
325 local keys_filtered = { }
326 for _, k in pairs(keys) do
327 for _, et in pairs({...}) do
328 if type(t[k]) == et then
329 rtable.insert(keys_filtered, k)
330 break
334 return keys_filtered
337 --- Reverse a table
338 -- @param t the table to reverse
339 -- @return the reversed table
340 function table.reverse(t)
341 local tr = { }
342 -- reverse all elements with integer keys
343 for _, v in ipairs(t) do
344 rtable.insert(tr, 1, v)
346 -- add the remaining elements
347 for k, v in pairs(t) do
348 if type(k) ~= "number" then
349 tr[k] = v
352 return tr
355 --- Clone a table
356 -- @param t the table to clone
357 -- @return a clone of t
358 function table.clone(t)
359 local c = { }
360 for k, v in pairs(t) do
361 c[k] = v
363 return c
367 -- Returns an iterator to cycle through, starting from the first element or the
368 -- given index, all elments of a table that match a given criteria.
369 -- @param t the table to iterate
370 -- @param filter a function that returns true to indicate a positive match
371 -- @param start what index to start iterating from. Default is 1 (=> start of
372 -- the table)
373 function table.cycle(t, filter, start)
374 local count = 0
375 local index = start or 1
376 local length = #t
378 return function ()
379 while count < length do
380 local item = t[index]
381 index = cycle(#t, index + 1)
382 count = count + 1
383 if filter(item) then return item end
387 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80