diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py --- a/mercurial/hgweb/webutil.py +++ b/mercurial/hgweb/webutil.py @@ -713,6 +713,10 @@ class sessionvars(templateutil.wrapped): def __copy__(self): return sessionvars(copy.copy(self._vars), self._start) + def contains(self, context, mapping, item): + item = templateutil.unwrapvalue(context, mapping, item) + return item in self._vars + def getmember(self, context, mapping, key): key = templateutil.unwrapvalue(context, mapping, key) return self._vars.get(key) diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -291,13 +291,10 @@ def ifcontains(context, mapping, args): # i18n: "ifcontains" is a keyword raise error.ParseError(_("ifcontains expects three or four arguments")) - haystack = evalfuncarg(context, mapping, args[1]) - keytype = getattr(haystack, 'keytype', None) + haystack = evalwrapped(context, mapping, args[1]) try: needle = evalrawexp(context, mapping, args[0]) - needle = templateutil.unwrapastype(context, mapping, needle, - keytype or bytes) - found = (needle in haystack) + found = haystack.contains(context, mapping, needle) except error.ParseError: found = False diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py --- a/mercurial/templateutil.py +++ b/mercurial/templateutil.py @@ -38,6 +38,13 @@ class wrapped(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod + def contains(self, context, mapping, item): + """Test if the specified item is in self + + The item argument may be a wrapped object. + """ + + @abc.abstractmethod def getmember(self, context, mapping, key): """Return a member item for the specified key @@ -91,6 +98,10 @@ class wrappedbytes(wrapped): def __init__(self, value): self._value = value + def contains(self, context, mapping, item): + item = stringify(context, mapping, item) + return item in self._value + def getmember(self, context, mapping, key): raise error.ParseError(_('%r is not a dictionary') % pycompat.bytestr(self._value)) @@ -125,6 +136,9 @@ class wrappedvalue(wrapped): def __init__(self, value): self._value = value + def contains(self, context, mapping, item): + raise error.ParseError(_("%r is not iterable") % self._value) + def getmember(self, context, mapping, key): raise error.ParseError(_('%r is not a dictionary') % self._value) @@ -171,6 +185,10 @@ class hybrid(wrapped): self._joinfmt = joinfmt self.keytype = keytype # hint for 'x in y' where type(x) is unresolved + def contains(self, context, mapping, item): + item = unwrapastype(context, mapping, item, self.keytype) + return item in self._values + def getmember(self, context, mapping, key): # TODO: maybe split hybrid list/dict types? if not util.safehasattr(self._values, 'get'): @@ -255,6 +273,10 @@ class mappable(wrapped): def tomap(self): return self._makemap(self._key) + def contains(self, context, mapping, item): + w = makewrapped(context, mapping, self._value) + return w.contains(context, mapping, item) + def getmember(self, context, mapping, key): w = makewrapped(context, mapping, self._value) return w.getmember(context, mapping, key) @@ -302,6 +324,9 @@ class _mappingsequence(wrapped): self._tmpl = tmpl self._defaultsep = sep + def contains(self, context, mapping, item): + raise error.ParseError(_('not comparable')) + def getmember(self, context, mapping, key): raise error.ParseError(_('not a dictionary')) @@ -371,6 +396,10 @@ class mappedgenerator(wrapped): self._make = make self._args = args + def contains(self, context, mapping, item): + item = stringify(context, mapping, item) + return item in self.tovalue(context, mapping) + def _gen(self, context): return self._make(context, *self._args) diff --git a/tests/test-command-template.t b/tests/test-command-template.t --- a/tests/test-command-template.t +++ b/tests/test-command-template.t @@ -4166,6 +4166,15 @@ Test ifcontains function 1 0 + $ hg log -l1 -T '{ifcontains("branch", extras, "t", "f")}\n' + t + $ hg log -l1 -T '{ifcontains("branch", extras % "{key}", "t", "f")}\n' + t + $ hg log -l1 -T '{ifcontains("branc", extras % "{key}", "t", "f")}\n' + f + $ hg log -l1 -T '{ifcontains("branc", stringify(extras % "{key}"), "t", "f")}\n' + t + Test revset function $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'