diff options
Diffstat (limited to 'awesome/lib/awful/util.lua')
-rw-r--r-- | awesome/lib/awful/util.lua | 588 |
1 files changed, 0 insertions, 588 deletions
diff --git a/awesome/lib/awful/util.lua b/awesome/lib/awful/util.lua deleted file mode 100644 index 8dcb955..0000000 --- a/awesome/lib/awful/util.lua +++ /dev/null @@ -1,588 +0,0 @@ ---------------------------------------------------------------------------- ---- Utility module for awful --- --- @author Julien Danjou <julien@danjou.info> --- @copyright 2008 Julien Danjou --- @module awful.util ---------------------------------------------------------------------------- - --- Grab environment we need -local os = os -local assert = assert -local load = loadstring or load -- luacheck: globals loadstring (compatibility with Lua 5.1) -local loadfile = loadfile -local debug = debug -local pairs = pairs -local ipairs = ipairs -local type = type -local rtable = table -local string = string -local lgi = require("lgi") -local grect = require("gears.geometry").rectangle -local Gio = require("lgi").Gio -local Pango = lgi.Pango -local capi = -{ - awesome = awesome, - mouse = mouse -} -local gears_debug = require("gears.debug") -local floor = math.floor - -local util = {} -util.table = {} - ---- The default shell used when spawing processes. -util.shell = os.getenv("SHELL") or "/bin/sh" - -local displayed_deprecations = {} ---- Display a deprecation notice, but only once per traceback. --- @param[opt] see The message to a new method / function to use. --- @tparam table args Extra arguments --- @tparam boolean args.raw Print the message as-is without the automatic context -function util.deprecate(see, args) - args = args or {} - local tb = debug.traceback() - if displayed_deprecations[tb] then - return - end - displayed_deprecations[tb] = true - - -- Get function name/desc from caller. - local info = debug.getinfo(2, "n") - local funcname = info.name or "?" - local msg = "awful: function " .. funcname .. " is deprecated" - if see then - if args.raw then - msg = see - elseif string.sub(see, 1, 3) == 'Use' then - msg = msg .. ". " .. see - else - msg = msg .. ", see " .. see - end - end - gears_debug.print_warning(msg .. ".\n" .. tb) -end - ---- Create a class proxy with deprecation messages. --- This is useful when a class has moved somewhere else. --- @tparam table fallback The new class --- @tparam string old_name The old class name --- @tparam string new_name The new class name --- @treturn table A proxy class. -function util.deprecate_class(fallback, old_name, new_name) - local message = old_name.." has been renamed to "..new_name - - local function call(_,...) - util.deprecate(message) - - return fallback(...) - end - - local function index(_, k) - util.deprecate(message) - - return fallback[k] - end - - local function newindex(_, k, v) - util.deprecate(message, {raw = true}) - - fallback[k] = v - end - - return setmetatable({}, {__call = call, __index = index, __newindex = newindex}) -end - ---- Get a valid color for Pango markup --- @param color The color. --- @tparam string fallback The color to return if the first is invalid. (default: black) --- @treturn string color if it is valid, else fallback. -function util.ensure_pango_color(color, fallback) - color = tostring(color) - return Pango.Color.parse(Pango.Color(), color) and color or fallback or "black" -end - ---- Make i cycle. --- @param t A length. Must be greater than zero. --- @param i An absolute index to fit into #t. --- @return An integer in (1, t) or nil if t is less than or equal to zero. -function util.cycle(t, i) - if t < 1 then return end - i = i % t - if i == 0 then - i = t - end - return i -end - ---- Create a directory --- @param dir The directory. --- @return mkdir return code -function util.mkdir(dir) - return os.execute("mkdir -p " .. dir) -end - ---- Eval Lua code. --- @return The return value of Lua code. -function util.eval(s) - return assert(load(s))() -end - -local xml_entity_names = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" }; ---- Escape a string from XML char. --- Useful to set raw text in textbox. --- @param text Text to escape. --- @return Escape text. -function util.escape(text) - return text and text:gsub("['&<>\"]", xml_entity_names) or nil -end - -local xml_entity_chars = { lt = "<", gt = ">", nbsp = " ", quot = "\"", apos = "'", ndash = "-", mdash = "-", amp = "&" }; ---- Unescape a string from entities. --- @param text Text to unescape. --- @return Unescaped text. -function util.unescape(text) - return text and text:gsub("&(%a+);", xml_entity_chars) or nil -end - ---- Check if a file is a Lua valid file. --- This is done by loading the content and compiling it with loadfile(). --- @param path The file path. --- @return A function if everything is alright, a string with the error --- otherwise. -function util.checkfile(path) - local f, e = loadfile(path) - -- Return function if function, otherwise return error. - if f then return f end - return e -end - ---- Try to restart awesome. --- It checks if the configuration file is valid, and then restart if it's ok. --- If it's not ok, the error will be returned. --- @return Never return if awesome restart, or return a string error. -function util.restart() - local c = util.checkfile(capi.awesome.conffile) - - if type(c) ~= "function" then - return c - end - - capi.awesome.restart() -end - ---- Get the config home according to the XDG basedir specification. --- @return the config home (XDG_CONFIG_HOME) with a slash at the end. -function util.get_xdg_config_home() - return (os.getenv("XDG_CONFIG_HOME") or os.getenv("HOME") .. "/.config") .. "/" -end - ---- Get the cache home according to the XDG basedir specification. --- @return the cache home (XDG_CACHE_HOME) with a slash at the end. -function util.get_xdg_cache_home() - return (os.getenv("XDG_CACHE_HOME") or os.getenv("HOME") .. "/.cache") .. "/" -end - ---- Get the path to the user's config dir. --- This is the directory containing the configuration file ("rc.lua"). --- @return A string with the requested path with a slash at the end. -function util.get_configuration_dir() - return capi.awesome.conffile:match(".*/") or "./" -end - ---- Get the path to a directory that should be used for caching data. --- @return A string with the requested path with a slash at the end. -function util.get_cache_dir() - return util.get_xdg_cache_home() .. "awesome/" -end - ---- Get the path to the directory where themes are installed. --- @return A string with the requested path with a slash at the end. -function util.get_themes_dir() - return "/usr/share/awesome/themes" .. "/" -end - ---- Get the path to the directory where our icons are installed. --- @return A string with the requested path with a slash at the end. -function util.get_awesome_icon_dir() - return "/usr/share/awesome/icons" .. "/" -end - ---- Get the user's config or cache dir. --- It first checks XDG_CONFIG_HOME / XDG_CACHE_HOME, but then goes with the --- default paths. --- @param d The directory to get (either "config" or "cache"). --- @return A string containing the requested path. -function util.getdir(d) - if d == "config" then - -- No idea why this is what is returned, I recommend everyone to use - -- get_configuration_dir() instead - return util.get_xdg_config_home() .. "awesome/" - elseif d == "cache" then - return util.get_cache_dir() - end -end - ---- Search for an icon and return the full path. --- It searches for the icon path under the given directories with respect to the --- given extensions for the icon filename. --- @param iconname The name of the icon to search for. --- @param exts Table of image extensions allowed, otherwise { 'png', gif' } --- @param dirs Table of dirs to search, otherwise { '/usr/share/pixmaps/' } --- @tparam[opt] string size The size. If this is specified, subdirectories `x` --- of the dirs are searched first. -function util.geticonpath(iconname, exts, dirs, size) - exts = exts or { 'png', 'gif' } - dirs = dirs or { '/usr/share/pixmaps/', '/usr/share/icons/hicolor/' } - local icontypes = { 'apps', 'actions', 'categories', 'emblems', - 'mimetypes', 'status', 'devices', 'extras', 'places', 'stock' } - for _, d in pairs(dirs) do - local icon - for _, e in pairs(exts) do - icon = d .. iconname .. '.' .. e - if util.file_readable(icon) then - return icon - end - if size then - for _, t in pairs(icontypes) do - icon = string.format("%s%ux%u/%s/%s.%s", d, size, size, t, iconname, e) - if util.file_readable(icon) then - return icon - end - end - end - end - end -end - ---- Check if a file exists, is not readable and not a directory. --- @param filename The file path. --- @return True if file exists and is readable. -function util.file_readable(filename) - local gfile = Gio.File.new_for_path(filename) - local gfileinfo = gfile:query_info("standard::type,access::can-read", - Gio.FileQueryInfoFlags.NONE) - return gfileinfo and gfileinfo:get_file_type() ~= "DIRECTORY" and - gfileinfo:get_attribute_boolean("access::can-read") -end - ---- Check if a path exists, is readable and is a directory. --- @tparam string path The directory path. --- @treturn boolean True if dir exists and is readable. -function util.dir_readable(path) - local gfile = Gio.File.new_for_path(path) - local gfileinfo = gfile:query_info("standard::type,access::can-read", - Gio.FileQueryInfoFlags.NONE) - return gfileinfo and gfileinfo:get_file_type() == "DIRECTORY" and - gfileinfo:get_attribute_boolean("access::can-read") -end - ---- Check if a path is a directory. --- @tparam string path --- @treturn bool True if path exists and is a directory. -function util.is_dir(path) - return Gio.File.new_for_path(path):query_file_type({}) == "DIRECTORY" -end - -local function subset_mask_apply(mask, set) - local ret = {} - for i = 1, #set do - if mask[i] then - rtable.insert(ret, set[i]) - end - end - return ret -end - -local function subset_next(mask) - local i = 1 - while i <= #mask and mask[i] do - mask[i] = false - i = i + 1 - end - - if i <= #mask then - mask[i] = 1 - return true - end - return false -end - ---- Return all subsets of a specific set. --- This function, giving a set, will return all subset it. --- For example, if we consider a set with value { 10, 15, 34 }, --- it will return a table containing 2^n set: --- { }, { 10 }, { 15 }, { 34 }, { 10, 15 }, { 10, 34 }, etc. --- @param set A set. --- @return A table with all subset. -function util.subsets(set) - local mask = {} - local ret = {} - for i = 1, #set do mask[i] = false end - - -- Insert the empty one - rtable.insert(ret, {}) - - while subset_next(mask) do - rtable.insert(ret, subset_mask_apply(mask, set)) - end - return ret -end - ---- Get the nearest rectangle in the given direction. Every rectangle is specified as a table --- with 'x', 'y', 'width', 'height' keys, the same as client or screen geometries. --- @deprecated awful.util.get_rectangle_in_direction --- @param dir The direction, can be either "up", "down", "left" or "right". --- @param recttbl A table of rectangle specifications. --- @param cur The current rectangle. --- @return The index for the rectangle in recttbl closer to cur in the given direction. nil if none found. --- @see gears.geometry -function util.get_rectangle_in_direction(dir, recttbl, cur) - util.deprecate("gears.geometry.rectangle.get_in_direction") - - return grect.get_in_direction(dir, recttbl, cur) -end - ---- Join all tables given as parameters. --- This will iterate all tables and insert all their keys into a new table. --- @param args A list of tables to join --- @return A new table containing all keys from the arguments. -function util.table.join(...) - local ret = {} - for _, t in pairs({...}) do - if t then - for k, v in pairs(t) do - if type(k) == "number" then - rtable.insert(ret, v) - else - ret[k] = v - end - end - end - end - return ret -end - ---- Override elements in the first table by the one in the second. --- --- Note that this method doesn't copy entries found in `__index`. --- @tparam table t the table to be overriden --- @tparam table set the table used to override members of `t` --- @tparam[opt=false] boolean raw Use rawset (avoid the metatable) --- @treturn table t (for convenience) -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 - ---- Pack all elements with an integer key into a new table --- While both lua and luajit implement __len over sparse --- table, the standard define it as an implementation --- detail. --- --- This function remove any non numeric keys from the value set --- --- @tparam table t A potentially sparse table --- @treturn table A packed table with all numeric keys -function util.table.from_sparse(t) - local keys= {} - for k in pairs(t) do - if type(k) == "number" then - keys[#keys+1] = k - end - end - - table.sort(keys) - - local ret = {} - for _,v in ipairs(keys) do - ret[#ret+1] = t[v] - end - - return ret -end - ---- Check if a table has an item and return its key. --- @param t The table. --- @param item The item to look for in values of the table. --- @return The key were the item is found, or nil if not found. -function util.table.hasitem(t, item) - for k, v in pairs(t) do - if v == item then - return k - end - end -end - ---- Split a string into multiple lines --- @param text String to wrap. --- @param width Maximum length of each line. Default: 72. --- @param indent Number of spaces added before each wrapped line. Default: 0. --- @return The string with lines wrapped to width. -function util.linewrap(text, width, indent) - text = text or "" - width = width or 72 - indent = indent or 0 - - local pos = 1 - return text:gsub("(%s+)()(%S+)()", - function(_, st, word, fi) - if fi - pos > width then - pos = st - return "\n" .. string.rep(" ", indent) .. word - end - end) -end - ---- Count number of lines in a string --- @tparam string text Input string. --- @treturn int Number of lines. -function util.linecount(text) - return select(2, text:gsub('\n', '\n')) + 1 -end - ---- Get a sorted table with all integer keys from a table --- @param t the table for which the keys to get --- @return A table with keys -function util.table.keys(t) - local keys = { } - for k, _ in pairs(t) do - rtable.insert(keys, k) - end - rtable.sort(keys, function (a, b) - return type(a) == type(b) and a < b or false - end) - return keys -end - ---- Filter a tables keys for certain content types --- @param t The table to retrieve the keys for --- @param ... the types to look for --- @return A filtered table with keys -function util.table.keys_filter(t, ...) - local keys = util.table.keys(t) - local keys_filtered = { } - for _, k in pairs(keys) do - for _, et in pairs({...}) do - if type(t[k]) == et then - rtable.insert(keys_filtered, k) - break - end - end - end - return keys_filtered -end - ---- Reverse a table --- @param t the table to reverse --- @return the reversed table -function util.table.reverse(t) - local tr = { } - -- reverse all elements with integer keys - for _, v in ipairs(t) do - rtable.insert(tr, 1, v) - end - -- add the remaining elements - for k, v in pairs(t) do - if type(k) ~= "number" then - tr[k] = v - end - end - return tr -end - ---- Clone a table --- @param t the table to clone --- @param deep Create a deep clone? (default: true) --- @return a clone of t -function util.table.clone(t, deep) - deep = deep == nil and true or deep - local c = { } - for k, v in pairs(t) do - if deep and type(v) == "table" then - c[k] = util.table.clone(v) - else - c[k] = v - end - end - return c -end - ---- --- Returns an iterator to cycle through, starting from the first element or the --- given index, all elements of a table that match a given criteria. --- --- @param t the table to iterate --- @param filter a function that returns true to indicate a positive match --- @param start what index to start iterating from. Default is 1 (=> start of --- the table) -function util.table.iterate(t, filter, start) - local count = 0 - local index = start or 1 - local length = #t - - return function () - while count < length do - local item = t[index] - index = util.cycle(#t, index + 1) - count = count + 1 - if filter(item) then return item end - end - end -end - - ---- Merge items from the one table to another one --- @tparam table t the container table --- @tparam table set the mixin table --- @treturn table Return `t` for convenience -function util.table.merge(t, set) - for _, v in ipairs(set) do - table.insert(t, v) - end - return t -end - - --- Escape all special pattern-matching characters so that lua interprets them --- literally instead of as a character class. --- Source: http://stackoverflow.com/a/20778724/15690 -function util.quote_pattern(s) - -- All special characters escaped in a string: %%, %^, %$, ... - local patternchars = '['..("%^$().[]*+-?"):gsub("(.)", "%%%1")..']' - return string.gsub(s, patternchars, "%%%1") -end - --- Generate a pattern matching expression that ignores case. --- @param s Original pattern matching expression. -function util.query_to_pattern(q) - local s = util.quote_pattern(q) - -- Poor man's case-insensitive character matching. - s = string.gsub(s, "%a", - function (c) - return string.format("[%s%s]", string.lower(c), - string.upper(c)) - end) - return s -end - ---- Round a number to an integer. --- @tparam number x --- @treturn integer -function util.round(x) - return floor(x + 0.5) -end - -return util - --- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 |