diff mercurial/templatefuncs.py @ 38454:bc8d925342f0

templater: extend filter() to accept template expression for emptiness test This utilizes the pass-by-name nature of template arguments.
author Yuya Nishihara <yuya@tcha.org>
date Thu, 14 Jun 2018 23:10:14 +0900
parents dae829b4de78
children 3588e41f796d
line wrap: on
line diff
--- a/mercurial/templatefuncs.py	Thu Jun 14 22:33:26 2018 +0900
+++ b/mercurial/templatefuncs.py	Thu Jun 14 23:10:14 2018 +0900
@@ -166,15 +166,23 @@
 
     return templatefilters.fill(text, width, initindent, hangindent)
 
-@templatefunc('filter(iterable)')
+@templatefunc('filter(iterable[, expr])')
 def filter_(context, mapping, args):
-    """Remove empty elements from a list or a dict."""
-    if len(args) != 1:
+    """Remove empty elements from a list or a dict. If expr specified, it's
+    applied to each element to test emptiness."""
+    if not (1 <= len(args) <= 2):
         # i18n: "filter" is a keyword
-        raise error.ParseError(_("filter expects one argument"))
+        raise error.ParseError(_("filter expects one or two arguments"))
     iterable = evalwrapped(context, mapping, args[0])
-    def select(w):
-        return w.tobool(context, mapping)
+    if len(args) == 1:
+        def select(w):
+            return w.tobool(context, mapping)
+    else:
+        def select(w):
+            if not isinstance(w, templateutil.mappable):
+                raise error.ParseError(_("not filterable by expression"))
+            lm = context.overlaymap(mapping, w.tomap(context))
+            return evalboolean(context, lm, args[1])
     return iterable.filter(context, mapping, select)
 
 @templatefunc('formatnode(node)', requires={'ui'})