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)
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.
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
63 --- Create a directory
64 -- @param dir The directory.
65 -- @return mkdir return code
67 return os
.execute("mkdir -p " .. dir
)
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
)
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
)
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.
96 if cmd
and cmd
~= "" then
97 local f
, err
= io
.popen(cmd
, 'r')
99 local s
= f
:read("*all")
109 -- @return The return value of Lua code.
111 return assert(loadstring(s
))()
114 local xml_entity_names
= { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" };
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
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
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.
148 local c
= checkfile(capi
.awesome
.conffile
)
150 if type(c
) ~= "function" then
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
160 -- @param d The directory to get (either "config" or "cache").
161 -- @return A string containing the requested path.
163 if d
== "config" then
164 local dir
= os
.getenv("XDG_CONFIG_HOME")
166 return dir
.. "/awesome"
168 return os
.getenv("HOME") .. "/.config/awesome"
169 elseif d
== "cache" then
170 local dir
= os
.getenv("XDG_CACHE_HOME")
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
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
)
208 local function subset_mask_apply(mask
, set
)
212 rtable
.insert(ret
, set
[i
])
218 local function subset_next(mask
)
220 while i
<= #mask
and mask
[i
] do
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.
238 -- @return A table with all subset.
239 function subsets(set
)
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
))
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(...)
259 for i
, t
in ipairs({...}) do
261 for k
, v
in pairs(t
) do
262 if type(k
) == "number" then
263 rtable
.insert(ret
, v
)
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
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
296 return text
:gsub("(%s+)()(%S+)()",
297 function(sp
, st
, word
, fi
)
298 if fi
- pos
> width
then
300 return "\n" .. string.rep(" ", indent
) .. word
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
)
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
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
)
338 -- @param t the table to reverse
339 -- @return the reversed table
340 function table.reverse(t
)
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
356 -- @param t the table to clone
357 -- @return a clone of t
358 function table.clone(t
)
360 for k
, v
in pairs(t
) do
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
373 function table.cycle(t
, filter
, start
)
375 local index
= start
or 1
379 while count
< length
do
380 local item
= t
[index
]
381 index
= cycle(#t
, index
+ 1)
383 if filter(item
) then return item
end
387 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80