From 64bef57013b5d8b1354d1d580f1523f0ab899072 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 28 Jul 2019 18:51:57 -0400 Subject: [PATCH] matcher: Add a `greater` and `lesser` matching sections. In a perfect world we would have pure expression matching, but that's problematic with all the "metaness" of the code. For now, this adds an imperfect way to match the minimum and maximum of number properties. It will be used by the screen rules for the DPI and size properties. --- lib/gears/matcher.lua | 78 ++++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/lib/gears/matcher.lua b/lib/gears/matcher.lua index 9929eaa69..300b26b40 100644 --- a/lib/gears/matcher.lua +++ b/lib/gears/matcher.lua @@ -76,41 +76,47 @@ local matcher = {} -- @tparam table gears.matcher The matcher. -- @see remove_matching_source +local function default_matcher(a, b) + return a == b or (type(a) == "string" and a:match(b)) +end + +local function greater_matcher(a, b) + return a > b +end + +local function lesser_matcher(a, b) + return a < b +end + -- 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) +-- @method _match +function matcher:_match(o, rule, matcher_f) if not rule then return false end + + matcher_f = matcher_f or default_matcher + for field, value in pairs(rule) do local pm = self._private.prop_matchers[field] - if pm then - if not pm(o, value, field) then - return false - end - elseif o[field] ~= nil 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 + if pm and pm(o, value, field) then + return true + elseif not matcher_f(o[field], value) then return false end end return true end -local function field_matcher(self, o, field, value) +local function field_matcher(self, o, field, value, matcher_f) + matcher_f = matcher_f or default_matcher + local pm = self._private.prop_matchers[field] if pm and pm(o, value, field) then return true - elseif o[field] == value then - return true - elseif type(o[field]) == "string" and o[field]:match(value) then + elseif matcher_f(o[field] , value) then return true end @@ -121,12 +127,21 @@ end -- @param o The object. -- #tparam table rule The rule _match_anyto check. -- @treturn boolean True if at least one rule is matched, false otherwise. +-- @method _match_any function matcher:_match_any(o, rule) if not rule then return false end for field, values in pairs(rule) do if o[field] then + + -- Special case, "all" + if type(values) == "boolean" and values then + return true + end + for _, value in ipairs(values) do - if field_matcher(self, o, field, value) then return true end + if field_matcher(self, o, field, value) then + return true + end end end end @@ -140,6 +155,7 @@ end -- @tparam table rule The rule _match_anyto check. -- @tparam boolean multi If the entries are table of choices. -- @treturn boolean True if all rules are matched. +-- @method _match_every function matcher:_match_every(o, rule) if not rule then return true end @@ -168,10 +184,26 @@ end -- @method matches_rule function matcher:matches_rule(o, entry) local match = self:_match(o, entry.rule) or self:_match_any(o, entry.rule_any) - return match - and self:_match_every (o, entry.rule_every) - and (not self:_match (o, entry.except )) - and (not self:_match_any (o, entry.except_any)) + + -- If there was `rule` or `rule_any` and they failed to match, look no further. + if (not match) and (entry.rule or entry.rule_any) then return false end + + if not self:_match_every(o, entry.rule_every) then return false end + + -- Negative matching. + if entry.except and self:_match(o, entry.except) then return false end + if entry.except_any and self:_match_any(o, entry.except_any) then return false end + + -- Other operators. + if entry.rule_greater and not self:_match(o, entry.rule_greater, greater_matcher) then + return false + end + + if entry.rule_lesser and not self:_match(o, entry.rule_lesser, lesser_matcher) then + return false + end + + return true end --- Get list of matching rules for an object.