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.
This commit is contained in:
Emmanuel Lepage Vallee 2019-07-28 18:51:57 -04:00
parent 2dc8c62b9b
commit 64bef57013
1 changed files with 55 additions and 23 deletions

View File

@ -76,41 +76,47 @@ local matcher = {}
-- @tparam table gears.matcher The matcher. -- @tparam table gears.matcher The matcher.
-- @see remove_matching_source -- @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. -- Check if an object matches a rule.
-- @param o The object. -- @param o The object.
-- #tparam table rule The rule to check. -- #tparam table rule The rule to check.
-- @treturn boolean True if it matches, false otherwise. -- @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 if not rule then return false end
matcher_f = matcher_f or default_matcher
for field, value in pairs(rule) do for field, value in pairs(rule) do
local pm = self._private.prop_matchers[field] local pm = self._private.prop_matchers[field]
if pm then if pm and pm(o, value, field) then
if not pm(o, value, field) then return true
return false elseif not matcher_f(o[field], value) then
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
return false return false
end end
end end
return true return true
end 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] local pm = self._private.prop_matchers[field]
if pm and pm(o, value, field) then if pm and pm(o, value, field) then
return true return true
elseif o[field] == value then elseif matcher_f(o[field] , value) then
return true
elseif type(o[field]) == "string" and o[field]:match(value) then
return true return true
end end
@ -121,12 +127,21 @@ end
-- @param o The object. -- @param o The object.
-- #tparam table rule The rule _match_anyto check. -- #tparam table rule The rule _match_anyto check.
-- @treturn boolean True if at least one rule is matched, false otherwise. -- @treturn boolean True if at least one rule is matched, false otherwise.
-- @method _match_any
function matcher:_match_any(o, rule) function matcher:_match_any(o, rule)
if not rule then return false end if not rule then return false end
for field, values in pairs(rule) do for field, values in pairs(rule) do
if o[field] then if o[field] then
-- Special case, "all"
if type(values) == "boolean" and values then
return true
end
for _, value in ipairs(values) do 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 end
end end
@ -140,6 +155,7 @@ end
-- @tparam table rule The rule _match_anyto check. -- @tparam table rule The rule _match_anyto check.
-- @tparam boolean multi If the entries are table of choices. -- @tparam boolean multi If the entries are table of choices.
-- @treturn boolean True if all rules are matched. -- @treturn boolean True if all rules are matched.
-- @method _match_every
function matcher:_match_every(o, rule) function matcher:_match_every(o, rule)
if not rule then return true end if not rule then return true end
@ -168,10 +184,26 @@ end
-- @method matches_rule -- @method matches_rule
function matcher:matches_rule(o, entry) function matcher:matches_rule(o, entry)
local match = self:_match(o, entry.rule) or self:_match_any(o, entry.rule_any) 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) -- If there was `rule` or `rule_any` and they failed to match, look no further.
and (not self:_match (o, entry.except )) if (not match) and (entry.rule or entry.rule_any) then return false end
and (not self:_match_any (o, entry.except_any))
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 end
--- Get list of matching rules for an object. --- Get list of matching rules for an object.