1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2008 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 -- Grab environment we need
11 local loadstring
= loadstring
12 local loadfile
= loadfile
26 --- Utility module for awful
31 shell
= os
.getenv("SHELL") or "/bin/sh"
33 function deprecate(see
)
34 io
.stderr
:write("W: awful: function is deprecated")
36 io
.stderr
:write(", see " .. see
)
39 io
.stderr
:write(debug
.traceback())
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)
54 -- @param i An absolute index to fit into #t.
55 -- @return The object at new index.
57 while i
> t
do i
= i
- t
end
58 while i
< 1 do i
= i
+ t
end
62 --- Create a directory
63 -- @param dir The directory.
64 -- @return mkdir return code
66 return os
.execute("mkdir -p " .. dir
)
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
)
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
)
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.
95 if cmd
and cmd
~= "" then
96 local f
, err
= io
.popen(cmd
, 'r')
98 local s
= f
:read("*all")
108 -- @return The return value of Lua code.
110 return assert(loadstring(s
))()
113 local xml_entity_names
= { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" };
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
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
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.
147 local c
= checkfile(capi
.awesome
.conffile
)
149 if type(c
) ~= "function" then
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
159 -- @param d The directory to get (either "config" or "cache").
160 -- @return A string containing the requested path.
162 if d
== "config" then
163 local dir
= os
.getenv("XDG_CONFIG_HOME")
165 return dir
.. "/awesome"
167 return os
.getenv("HOME") .. "/.config/awesome"
168 elseif d
== "cache" then
169 local dir
= os
.getenv("XDG_CACHE_HOME")
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
)
189 local function subset_mask_apply(mask
, set
)
193 rtable
.insert(ret
, set
[i
])
199 local function subset_next(mask
)
201 while i
<= #mask
and mask
[i
] do
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.
219 -- @return A table with all subset.
220 function subsets(set
)
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
))
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(...)
242 for k
, v
in pairs(arg
[i
]) do
243 if type(k
) == "number" then
244 rtable
.insert(ret
, v
)
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
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
277 return text
:gsub("(%s+)()(%S+)()",
278 function(sp
, st
, word
, fi
)
279 if fi
- pos
> width
then
281 return "\n" .. string.rep(" ", indent
) .. word
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
)
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
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
)
319 -- @param t the table to reverse
320 -- @return the reversed table
321 function table.reverse(t
)
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
337 -- @param t the table to clone
338 -- @return a clone of t
339 function table.clone(t
)
341 for k
, v
in pairs(t
) do
347 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80