From 9befa1ec32595020ac9584e34fed4b5a7303cb4c Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 24 Feb 2019 15:24:58 -0500 Subject: [PATCH 1/8] ldoc: Add a new "rulecomponent" section. It is going to be used by `awful.rules`, `gears.matcher`, `naughty.rules` and `selection.rules`. --- docs/config.ld | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/config.ld b/docs/config.ld index 5a264241..03ace1a5 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -69,8 +69,10 @@ new_type("clientlayout", "Client layouts", false, "param") new_type("sourcefunction", "List source functions", false) -- Document some callback prototypes new_type("callback", "Callback functions prototype", false, "Parameters") --- awful.rules sources +-- gears.matcher / awful.rules sources new_type("rulesources", "Rule sources", false, "param") +-- gears.matcher / awful.rules rule components +new_type("rulecomponent", "Rule components", false, "Type") -- Filter functions for the taglist/tasklist/layoutlist new_type("filterfunction", "List filters", false) -- Extra client properties available only in awful.rules/spawn constructs From fa801ac4412c3a07f4362d9abba13d0a982b97b1 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 24 Feb 2019 17:05:07 -0500 Subject: [PATCH 2/8] ldoc: Do not proces the drag_to_tag file It has no public doc. This avoids a warning. --- docs/config.ld | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/config.ld b/docs/config.ld index 03ace1a5..0e78667f 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -120,6 +120,7 @@ file = { '../lib/awful/init.lua', '../lib/awful/remote.lua', '../lib/awful/startup_notification.lua', + '../lib/awful/mouse/drag_to_tag.lua', '../lib/gears/init.lua', '../lib/wibox/layout/init.lua', '../lib/wibox/container/init.lua', From 58bafe8ef4579ef592cfd4ae675feb736765b720 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 24 Feb 2019 17:33:49 -0500 Subject: [PATCH 3/8] doc: Add a common documentation for for the rule components. --- docs/common/rule.ldoc | 46 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 docs/common/rule.ldoc diff --git a/docs/common/rule.ldoc b/docs/common/rule.ldoc new file mode 100644 index 00000000..1d2c0fc8 --- /dev/null +++ b/docs/common/rule.ldoc @@ -0,0 +1,46 @@ +--- + +--- A table which content will be used to set the target object properties. +-- +-- foo +-- +-- @rulecomponent properties +-- @param table +-- @see callbacks + +--TODO add ^ +-- @DOC_text_gears_matcher_properties_EXAMPLE@ + +--- A list of callback function to call *after* the properties have been apploed. +-- @rulecomponent callbacks +-- @param table +-- @see properties + +--- A table which content will be compared to the target object current properties. +-- +-- @rulecomponent rule +-- @param table +-- @see rule_any +-- @see except + +--- Similar to `rule`, but each entry is a table with multiple values. +-- +-- +-- @rulecomponent rule_any +-- @param table +-- @see rule +-- @see except_any + +--- The negative equivalent of `rule`. +-- +-- @rulecomponent except +-- @param table +-- @see rule +-- @see except_any + +--- The negative equivalent of `rule_any`. +-- +-- @rulecomponent except_any +-- @param table +-- @see rule +-- @see except From 74c2e7382e442f2f7ae8f2d51668497e365a6a0d Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Mon, 21 Jan 2019 02:35:18 -0500 Subject: [PATCH 4/8] gears: Extract the logic code from awful.rules into gears.matcher. The use case for this is to reuse the matching logic for other objects such as tags or notification. --- lib/gears/matcher.lua | 318 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 lib/gears/matcher.lua diff --git a/lib/gears/matcher.lua b/lib/gears/matcher.lua new file mode 100644 index 00000000..fac9ffc1 --- /dev/null +++ b/lib/gears/matcher.lua @@ -0,0 +1,318 @@ +--- A module to build a set of properties based on a graph of rules. +-- +-- Sources +-- ======= +-- +-- This module holds the business logic used by `awful.rules`. It provides an +-- object on which one can add sets of rules or, alternatively, functions. +-- In this module, the sets of rules or custom functions are called sources. +-- +-- The sources are used to build a property table. Once all sources are +-- evaluated, the `:apply()` method will set the properties on the target +-- object. +-- +-- Sources can have dependencies between them and the property table can only +-- be built if the sources graph can be resolved. +-- +-- Rules +-- ===== +-- +-- The `rules` sources themselves are composed, as the name imply, of a set of +-- rule. A rule is a table with a `properties` *or* `callbacks` attribute along +-- with either `rule` or `rule_any`. It is also possible to add an `except` or +-- `except_any` attribute to narrow the scope in which the rule is applied. +-- Here's a basic example of a minimal `gears.matcher`. +-- +-- @DOC_text_gears_matcher_default_EXAMPLE@ +-- +-- More examples are available in `awful.rules`. +-- +-- @author Julien Danjou <julien@danjou.info> +-- @copyright 2009 Julien Danjou +-- @see awful.rules +-- @module gears.matcher + +local gtable = require("gears.table") +local gsort = require("gears.sort") +local gdebug = require("gears.debug") +local protected_call = require("gears.protected_call") + +local matcher = {} + +-- Check if an object matches a rule. +-- @param o The object. +-- #tparam table rule The rule to check. +-- @treturn boolean True if it matches, false otherwise. +function matcher:_match(o, rule) + if not rule then return false end + for field, value in pairs(rule) do + if o[field] then + if type(o[field]) == "string" then + if not o[field]:match(value) and o[field] ~= value then + return false + end + elseif o[field] ~= value then + return false + end + else + return false + end + end + return true +end + +-- Check if an object matches any part of a rule. +-- @param o The object. +-- #tparam table rule The rule to check. +-- @treturn boolean True if at least one rule is matched, false otherwise. +function matcher:_match_any(o, rule) + if not rule then return false end + for field, values in pairs(rule) do + if o[field] then + for _, value in ipairs(values) do + if o[field] == value then + return true + elseif type(o[field]) == "string" and o[field]:match(value) then + return true + end + end + end + end + return false +end + +--- Does a given rule entry match an object? +-- @param o The object. +-- @tparam table entry Rule entry (with keys `rule`, `rule_any`, `except` and/or +-- `except_any`). +-- @treturn boolean If `o` matches `entry`. +function matcher:matches_rule(o, entry) + local match = self:_match(o, entry.rule) or self:_match_any(o, entry.rule_any) + return match + and (not self:_match(o, entry.except)) + and (not self:_match_any(o, entry.except_any)) +end + +--- Get list of matching rules for an object. +-- +-- If the `rules` argument is not provided, the rules added with +-- `add_matching_rules` will be used. +-- +-- @param o The object. +-- @tparam[opt=nil] table rules The rules to check. List with "rule", "rule_any", +-- "except" and "except_any" keys. +-- @treturn table The list of matched rules. +function matcher:matching_rules(o, rules) + local result = {} + for _, entry in ipairs(rules) do + if self:matches_rule(o, entry) then + table.insert(result, entry) + end + end + return result +end + +--- Check if an object matches a given set of rules. +-- @param o The object. +-- @tparam table rules The rules to check. List of tables with `rule`, +-- `rule_any`, `except` and `except_any` keys. +-- @treturn boolean True if at least one rule is matched, false otherwise. +function matcher:matches_rules(o, rules) + for _, entry in ipairs(rules) do + if self:matches_rule(o, entry) then + return true + end + end + return false +end + +local function default_rules_callback(self, o, props, callbacks, rules) + for _, entry in ipairs(self:matching_rules(o, rules)) do + gtable.crush(props, entry.properties or {}) + + if entry.callback then + table.insert(callbacks, entry.callback) + end + end +end + +--- Add a set of matching rules. +-- +-- @tparam string name The provider name. It must be unique. +-- @tparam table rules A set of rules (see how they work at the top of this +-- page). +-- @tparam[opt={}] table depends_on A list of names of sources this source +-- depends on (sources that must be executed *before* `name`). +-- @tparam[opt={}] table precede A list of names of sources this source has a +-- priority over. +-- @treturn boolean Returns false if a dependency conflict was found. +function matcher:add_matching_rules(name, rules, depends_on, precede) + local function matching_fct(_self, c, props, callbacks) + default_rules_callback(_self, c, props, callbacks, rules) + end + + self._matching_rules[name] = rules + + return self:add_matching_function(name, matching_fct, depends_on, precede) +end + +--- Add a matching function. +-- +-- @tparam string name The provider name. It must be unique. +-- @tparam function callback The callback that is called to produce properties. +-- @tparam gears.matcher callback.self The matcher object. +-- @param callback.o The object. +-- @tparam table callback.properties The current properties. The callback should +-- add to and overwrite properties in this table. +-- @tparam table callback.callbacks A table of all callbacks scheduled to be +-- executed after the main properties are applied. +-- @tparam[opt={}] table depends_on A list of names of sources this source depends on +-- (sources that must be executed *before* `name`). +-- @tparam[opt={}] table precede A list of names of sources this source has a +-- priority over. +-- @treturn boolean Returns false if a dependency conflict was found. +function matcher:add_matching_function(name, callback, depends_on, precede) + depends_on = depends_on or {} + precede = precede or {} + assert(type( depends_on ) == "table") + assert(type( precede ) == "table") + + for _, v in ipairs(self._matching_source) do + -- Names must be unique + assert( + v.name ~= name, + "Name must be unique, but '" .. name .. "' was already registered." + ) + end + + local new_sources = self._rule_source_sort:clone() + + new_sources:prepend(name, precede ) + new_sources:append (name, depends_on ) + + local res, err = new_sources:sort() + + if err then + gdebug.print_warning("Failed to add the rule source: "..err) + return false + end + + -- Only replace the source once the additions has been proven to be safe. + self._rule_source_sort = new_sources + + local callbacks = {} + + -- Get all callbacks for *existing* sources. + -- It is important to remember that names can be used in the sorting even + -- if the source itself doesn't (yet) exist. + for _, v in ipairs(self._matching_source) do + callbacks[v.name] = v.callback + end + + self._matching_source = {} + callbacks[name] = callback + + for _, v in ipairs(res) do + if callbacks[v] then + table.insert(self._matching_source, 1, { + callback = callbacks[v], + name = v + }) + end + end + + return true +end + +--- Remove a source. +-- +-- This removes sources added with `add_matching_function` or +-- `add_matching_rules`. +-- +-- @tparam string name The source name. +-- @treturn boolean If the source has been removed. +function matcher:remove_matching_source(name) + self._rule_source_sort:remove(name) + + for k, v in ipairs(self._matching_source) do + if v.name == name then + table.remove(self._matching_source, k) + return true + end + end + + self._matching_rules[name] = nil + + return false +end + +--- Apply awful.rules.rules to an object. +-- +-- Calling this will apply all properties provided by the matching functions +-- and rules. +-- +-- @param o The object. +function matcher:apply(o) + local callbacks, props = {}, {} + for _, v in ipairs(self._matching_source) do + v.callback(self, o, props, callbacks) + end + + self:_execute(o, props, callbacks) +end + +-- Execute the rules for the object `o`. +-- @param o The object. +-- @tparam table props A list of properties to apply. +-- @tparam table callbacks A list of callback to execute with the object `o` as +-- sole argument. The callbacks are executed *before* applying the properties. +-- @see gears.matcher.apply +function matcher:_execute(o, props, callbacks) + -- Apply all callbacks. + if callbacks then + for _, callback in pairs(callbacks) do + protected_call(callback, o) + end + end + + for property, value in pairs(props) do + if type(value) == "function" then + value = value(o, props) + end + + if type(o[property]) == "function" then + o[property](o, value) + else + o[property] = value + end + end +end + +local module = {} + +--- Create a new rule solver object. +-- @function gears.matcher +-- @return A new rule solver object. + +local function new() + local ret = {} + + -- Contains the sources. + -- The elements are ordered "first in, first executed". Thus, the higher the + -- index, the higher the priority. Each entry is a table with a `name` and a + -- `callback` field. This table is exposed for debugging purpose. The API + -- is private and should only be modified using the public accessors. + ret._matching_source = {} + ret._rule_source_sort = gsort.topological() + ret._matching_rules = {} + + gtable.crush(ret, matcher, true) + + return ret +end + +--@DOC_rule_COMMON@ + +--@DOC_object_COMMON@ + +return setmetatable(module, {__call = new}) From dc867ef36d187eb072eb542be38cb4d953e0d0ba Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 17 Feb 2019 14:30:00 -0500 Subject: [PATCH 5/8] tests: Add an example for gears.matcher --- tests/examples/text/gears/matcher/default.lua | 80 +++++++++++++++++++ .../text/gears/matcher/properties.lua | 24 ++++++ .../text/gears/matcher/properties.txt | 0 3 files changed, 104 insertions(+) create mode 100644 tests/examples/text/gears/matcher/default.lua create mode 100644 tests/examples/text/gears/matcher/properties.lua create mode 100644 tests/examples/text/gears/matcher/properties.txt diff --git a/tests/examples/text/gears/matcher/default.lua b/tests/examples/text/gears/matcher/default.lua new file mode 100644 index 00000000..ec60bc96 --- /dev/null +++ b/tests/examples/text/gears/matcher/default.lua @@ -0,0 +1,80 @@ +--DOC_HIDE --DOC_NO_USAGE --DOC_GEN_OUTPUT +local gears = {matcher = require("gears.matcher")} --DOC_HIDE + + local o = { + foo = "bar", + answer = 42, + } + +--DOC_NEWLINE + + -- This rule will match + local rule1 = { + rule = { + answer = 42, + }, + properties = { + name = "baz", + }, + } + +--DOC_NEWLINE + + -- This rule will **not** match + local rule2 = { + -- When the rule properties are strings, the Lua + --pattern matching is used. + rule = { + foo = "[f]+", + }, + properties = { + name = "foobar", + }, + } + +--DOC_NEWLINE + + local rules = { + rule1, + rule2, + } + +--DOC_NEWLINE + + local matcher = gears.matcher() + +--DOC_NEWLINE + + local function first_source(self, object, props, callbacks) --luacheck: no unused args + assert(self:matching_rules(object, rules)[1] == rule1) --DOC_HIDE + assert(#self:matching_rules(object, rules) == 1) --DOC_HIDE + assert(self:matches_rule(object, rule1)) --DOC_HIDE + assert(not self:matches_rule(object, rule2)) --DOC_HIDE + + -- In this callback, you can add new elements to the props and + -- callbacks tables. It is not recommended the modify `object` in + -- this callback. + if object.answer == 42 then + props.is_everything = true + end + end + +--DOC_NEWLINE + + -- This will add a custom function to add properties to the rules. + matcher:add_matching_function("first", first_source, {}, {}) + +--DOC_NEWLINE + + -- This will add the `rules` to this matcher. + matcher:add_matching_rules("second", rules, {"first"}, {}) + +--DOC_NEWLINE + + -- Apply the properties to `o` + matcher:apply(o) + +assert(o.is_everything) --DOC_HIDE +assert(o.name == "baz") --DOC_HIDE +matcher:remove_matching_source("first") --DOC_HIDE +matcher:remove_matching_source("second") --DOC_HIDE diff --git a/tests/examples/text/gears/matcher/properties.lua b/tests/examples/text/gears/matcher/properties.lua new file mode 100644 index 00000000..f9674598 --- /dev/null +++ b/tests/examples/text/gears/matcher/properties.lua @@ -0,0 +1,24 @@ +--DOC_HIDE +local gears = {matcher = require("gears.matcher")} --DOC_HIDE + +local o = { --DOC_HIDE + foo = "bar", --DOC_HIDE + answer = 42, --DOC_HIDE +} --DOC_HIDE + +local rules = { + { + rule = { + answer = 42, + }, + properties = { + name = "baz", + }, + } +} + +--DOC_NEWLINE + +local matcher = gears.matcher()--DOC_HIDE +matcher:add_matching_rules("second", rules, {"first"}, {}) --DOC_HIDE +matcher:apply(o) --DOC_HIDE diff --git a/tests/examples/text/gears/matcher/properties.txt b/tests/examples/text/gears/matcher/properties.txt new file mode 100644 index 00000000..e69de29b From 91bea445d2b2f984079929370dc06776db30d466 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Mon, 21 Jan 2019 02:36:07 -0500 Subject: [PATCH 6/8] awful.rules: Use gears.matcher Extract the code so it can be reused without pulling too many internal APIs with it. --- lib/awful/rules.lua | 158 +++++++++----------------------------------- 1 file changed, 30 insertions(+), 128 deletions(-) diff --git a/lib/awful/rules.lua b/lib/awful/rules.lua index 9780c63c..492f5ccc 100644 --- a/lib/awful/rules.lua +++ b/lib/awful/rules.lua @@ -119,8 +119,8 @@ local gtable = require("gears.table") local a_place = require("awful.placement") local protected_call = require("gears.protected_call") local aspawn = require("awful.spawn") -local gsort = require("gears.sort") local gdebug = require("gears.debug") +local gmatcher = require("gears.matcher") local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) local rules = {} @@ -128,26 +128,14 @@ local rules = {} --- This is the global rules table. rules.rules = {} +local crules = gmatcher() + --- Check if a client matches a rule. -- @client c The client. -- @tab rule The rule to check. -- @treturn bool True if it matches, false otherwise. function rules.match(c, rule) - if not rule then return false end - for field, value in pairs(rule) do - if c[field] then - if type(c[field]) == "string" then - if not c[field]:match(value) and c[field] ~= value then - return false - end - elseif c[field] ~= value then - return false - end - else - return false - end - end - return true + return crules:_match(c, rule) end --- Check if a client matches any part of a rule. @@ -155,19 +143,7 @@ end -- @tab rule The rule to check. -- @treturn bool True if at least one rule is matched, false otherwise. function rules.match_any(c, rule) - if not rule then return false end - for field, values in pairs(rule) do - if c[field] then - for _, value in ipairs(values) do - if c[field] == value then - return true - elseif type(c[field]) == "string" and c[field]:match(value) then - return true - end - end - end - end - return false + return crules:_match_any(c, rule) end --- Does a given rule entry match a client? @@ -176,8 +152,7 @@ end -- `except_any`). -- @treturn bool function rules.matches(c, entry) - return (rules.match(c, entry.rule) or rules.match_any(c, entry.rule_any)) and - (not rules.match(c, entry.except) and not rules.match_any(c, entry.except_any)) + return crules:matches_rule(c, entry) end --- Get list of matching rules for a client. @@ -186,13 +161,7 @@ end -- "except_any" keys. -- @treturn table The list of matched rules. function rules.matching_rules(c, _rules) - local result = {} - for _, entry in ipairs(_rules) do - if (rules.matches(c, entry)) then - table.insert(result, entry) - end - end - return result + return crules:matching_rules(c, _rules) end --- Check if a client matches a given set of rules. @@ -201,22 +170,22 @@ end -- `except` and `except_any` keys. -- @treturn bool True if at least one rule is matched, false otherwise. function rules.matches_list(c, _rules) - for _, entry in ipairs(_rules) do - if (rules.matches(c, entry)) then - return true - end - end - return false + return crules:matches_rules(c, _rules) +end + +--- Remove a source. +-- @tparam string name The source name. +-- @treturn boolean If the source was removed, +function rules.remove_rule_source(name) + return crules:remove_matching_source(name) end --- Contains the sources. --- The elements are ordered "first in, first executed". Thus, the higher the --- index, the higher the priority. Each entry is a table with a `name` and a --- `callback` field. This table is exposed for debugging purpose. The API --- is private and should be modified using the public accessors. -local rule_sources = {} -local rule_source_sort = gsort.topological() +--- Apply awful.rules.rules to a client. +-- @client c The client. +function rules.apply(c) + return crules:apply(c) +end --- Add a new rule source. -- @@ -257,73 +226,13 @@ local rule_source_sort = gsort.topological() -- @tparam[opt={}] table precede A list of names of sources this source have a -- priority over. -- @treturn boolean Returns false if a dependency conflict was found. -function rules.add_rule_source(name, callback, depends_on, precede) - depends_on = depends_on or {} - precede = precede or {} - assert(type( depends_on ) == "table") - assert(type( precede ) == "table") +-- @function awful.rules.add_rule_source - for _, v in ipairs(rule_sources) do - -- Names must be unique - assert( - v.name ~= name, - "Name must be unique, but '" .. name .. "' was already registered." - ) +function rules.add_rule_source(name, cb, ...) + local function callback(_, ...) + cb(...) end - - local new_sources = rule_source_sort:clone() - - new_sources:prepend(name, precede ) - new_sources:append (name, depends_on ) - - local res, err = new_sources:sort() - - if err then - gdebug.print_warning("Failed to add the rule source: "..err) - return false - end - - -- Only replace the source once the additions have been proven safe - rule_source_sort = new_sources - - local callbacks = {} - - -- Get all callbacks for *existing* sources. - -- It is important to remember that names can be used in the sorting even - -- if the source itself doesn't (yet) exists. - for _, v in ipairs(rule_sources) do - callbacks[v.name] = v.callback - end - - rule_sources = {} - callbacks[name] = callback - - for _, v in ipairs(res) do - if callbacks[v] then - table.insert(rule_sources, 1, { - callback = callbacks[v], - name = v - }) - end - end - - return true -end - ---- Remove a source. --- @tparam string name The source name. --- @treturn boolean If the source was removed -function rules.remove_rule_source(name) - rule_source_sort:remove(name) - - for k, v in ipairs(rule_sources) do - if v.name == name then - table.remove(rule_sources, k) - return true - end - end - - return false + return crules:add_matching_function(name, callback, ...) end -- Add the rules properties @@ -414,17 +323,6 @@ end rules.add_rule_source("awful.spawn_once", apply_singleton_rules, {"awful.spawn"}, {"awful.rules"}) ---- Apply awful.rules.rules to a client. --- @client c The client. -function rules.apply(c) - local callbacks, props = {}, {} - for _, v in ipairs(rule_sources) do - v.callback(c, props, callbacks) - end - - rules.execute(c, props, callbacks) -end - local function add_to_tag(c, t) if not t then return end @@ -621,7 +519,9 @@ end -- @client c The client. -- @tab props Properties to apply. -- @tab[opt] callbacks Callbacks to apply. -function rules.execute(c, props, callbacks) +-- @function awful.rules.execute + +crules._execute = function(_, c, props, callbacks) -- This has to be done first, as it will impact geometry related props. if props.titlebars_enabled and (type(props.titlebars_enabled) ~= "function" or props.titlebars_enabled(c,props)) then @@ -734,6 +634,8 @@ function rules.execute(c, props, callbacks) end end +function rules.execute(...) crules:_execute(...) end + -- TODO v5 deprecate this function rules.completed_with_payload_callback(c, props, callbacks) rules.execute(c, props, callbacks) From 0b4bb05b45f25bb49c1b4b942c2d2a7123bf2edf Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 24 Feb 2019 17:18:35 -0500 Subject: [PATCH 7/8] rules: Add a new documentation section for how to write a rule --- lib/awful/rules.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/awful/rules.lua b/lib/awful/rules.lua index 492f5ccc..9aa9db7d 100644 --- a/lib/awful/rules.lua +++ b/lib/awful/rules.lua @@ -643,6 +643,8 @@ end client.connect_signal("manage", rules.apply) +--@DOC_rule_COMMON@ + return rules -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 From 80cb6f299e7bb7874034e40edeb46fc790a60739 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 24 Feb 2019 17:20:19 -0500 Subject: [PATCH 8/8] doc: Fix an awful.autofocus warning --- lib/awful/autofocus.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/awful/autofocus.lua b/lib/awful/autofocus.lua index 8087f3da..5ec778be 100644 --- a/lib/awful/autofocus.lua +++ b/lib/awful/autofocus.lua @@ -43,7 +43,7 @@ end --- Give focus on tag selection change. -- --- @param tag A tag object +-- @tparam tag t A tag object local function check_focus_tag(t) local s = t.screen if (not s) or (not s.valid) then return end