# HG changeset patch # User Yuya Nishihara <y...@tcha.org> # Date 1528985414 -32400 # Thu Jun 14 23:10:14 2018 +0900 # Node ID f2d42f1933ce7e28647f2b834c86de3369fbbe00 # Parent f14965009644ab63cbe1990081493e8d490a30eb templater: extend filter() to accept template expression for emptiness test
This utilizes the pass-by-name nature of template arguments. diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -166,15 +166,23 @@ def fill(context, mapping, args): 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'}) diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py --- a/mercurial/templateutil.py +++ b/mercurial/templateutil.py @@ -415,6 +415,7 @@ class _mappingsequence(wrapped): raise error.ParseError(_('not comparable')) def filter(self, context, mapping, select): + # implement if necessary; we'll need a wrapped type for a mapping dict raise error.ParseError(_('not filterable without template')) def join(self, context, mapping, sep): diff --git a/tests/test-template-functions.t b/tests/test-template-functions.t --- a/tests/test-template-functions.t +++ b/tests/test-template-functions.t @@ -449,6 +449,13 @@ Test filter() empty values: $ hg log -R a -r 0 -T '{filter(revset("0:2"))}\n' 0 1 2 +Test filter() by expression: + + $ hg log -R a -r 1 -T '{filter(desc|splitlines, ifcontains("1", line, "t"))}\n' + other 1 + $ hg log -R a -r 0 -T '{filter(dict(a=0, b=1), ifeq(key, "b", "t"))}\n' + b=1 + Test filter() shouldn't crash: $ hg log -R a -r 0 -T '{filter(extras)}\n' @@ -459,7 +466,7 @@ Test filter() shouldn't crash: Test filter() unsupported arguments: $ hg log -R a -r 0 -T '{filter()}\n' - hg: parse error: filter expects one argument + hg: parse error: filter expects one or two arguments [255] $ hg log -R a -r 0 -T '{filter(date)}\n' hg: parse error: date is not iterable @@ -476,6 +483,9 @@ Test filter() unsupported arguments: $ hg log -R a -r 0 -T '{filter(succsandmarkers)}\n' hg: parse error: not filterable without template [255] + $ hg log -R a -r 0 -T '{filter(desc|splitlines % "{line}", "")}\n' + hg: parse error: not filterable by expression + [255] Test manifest/get() can be join()-ed as string, though it's silly: _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel