summaryrefslogtreecommitdiff
path: root/awesome/lib/awful/util.lua
diff options
context:
space:
mode:
Diffstat (limited to 'awesome/lib/awful/util.lua')
-rw-r--r--awesome/lib/awful/util.lua588
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 = { ["'"] = "&apos;", ["\""] = "&quot;", ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;" };
---- 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