# HG changeset patch # User Yuya Nishihara # Date 1504952005 -32400 # Node ID b3073e175c17d27005b8133569b165ea89ae7e0a # Parent 163fa0aea71ea8524036b248a3db2837866e1124 templater: wrap get/min/max result so map operation can apply to element See the test for usage example. wraphybridvalue() takes a key/value pair because a hybrid dict passes a key to its makemap() function. Since makemap() of showmanifest() doesn't need a key, it's set to None. diff -r 163fa0aea71e -r b3073e175c17 mercurial/templatekw.py --- a/mercurial/templatekw.py Mon Oct 02 07:18:24 2017 +0100 +++ b/mercurial/templatekw.py Sat Sep 09 19:13:25 2017 +0900 @@ -78,13 +78,18 @@ value. Use unwrapvalue() or unwraphybrid() to obtain the inner object. """ - def __init__(self, gen, value, makemap): - self.gen = gen + def __init__(self, gen, key, value, makemap): + if gen is not None: + self.gen = gen # generator or function returning generator + self._key = key self._value = value # may be generator of strings self._makemap = makemap + def gen(self): + yield pycompat.bytestr(self._value) + def tomap(self): - return self._makemap() + return self._makemap(self._key) def itermaps(self): yield self.tomap() @@ -114,6 +119,20 @@ return thing return thing._value +def wraphybridvalue(container, key, value): + """Wrap an element of hybrid container to be mappable + + The key is passed to the makemap function of the given container, which + should be an item generated by iter(container). + """ + makemap = getattr(container, '_makemap', None) + if makemap is None: + return value + if util.safehasattr(value, '_makemap'): + # a nested hybrid list/dict, which has its own way of map operation + return value + return _mappable(None, key, value, makemap) + def showdict(name, data, mapping, plural=None, key='key', value='value', fmt='%s=%s', separator=' '): c = [{key: k, value: v} for k, v in data.iteritems()] @@ -578,7 +597,7 @@ f = templ('manifest', **args) # TODO: perhaps 'ctx' should be dropped from mapping because manifest # rev and node are completely different from changeset's. - return _mappable(f, f, lambda: {'rev': mrev, 'node': mhex}) + return _mappable(f, None, f, lambda x: {'rev': mrev, 'node': mhex}) def shownames(namespace, **args): """helper method to generate a template keyword for a namespace""" diff -r 163fa0aea71e -r b3073e175c17 mercurial/templater.py --- a/mercurial/templater.py Mon Oct 02 07:18:24 2017 +0100 +++ b/mercurial/templater.py Sat Sep 09 19:13:25 2017 +0900 @@ -730,7 +730,10 @@ raise error.ParseError(_("get() expects a dict as first argument")) key = evalfuncarg(context, mapping, args[1]) - return dictarg.get(key) + val = dictarg.get(key) + if val is None: + return + return templatekw.wraphybridvalue(dictarg, key, val) @templatefunc('if(expr, then[, else])') def if_(context, mapping, args): @@ -874,10 +877,11 @@ iterable = evalfuncarg(context, mapping, args[0]) try: - return max(iterable) + x = max(iterable) except (TypeError, ValueError): # i18n: "max" is a keyword raise error.ParseError(_("max first argument should be an iterable")) + return templatekw.wraphybridvalue(iterable, x, x) @templatefunc('min(iterable)') def min_(context, mapping, args, **kwargs): @@ -888,10 +892,11 @@ iterable = evalfuncarg(context, mapping, args[0]) try: - return min(iterable) + x = min(iterable) except (TypeError, ValueError): # i18n: "min" is a keyword raise error.ParseError(_("min first argument should be an iterable")) + return templatekw.wraphybridvalue(iterable, x, x) @templatefunc('mod(a, b)') def mod(context, mapping, args): diff -r 163fa0aea71e -r b3073e175c17 tests/test-command-template.t --- a/tests/test-command-template.t Mon Oct 02 07:18:24 2017 +0100 +++ b/tests/test-command-template.t Sat Sep 09 19:13:25 2017 +0900 @@ -3128,10 +3128,24 @@ $ hg log -R latesttag -r tip -T '{manifest % "{rev}:{node}"}\n' 11:2bc6e9006ce29882383a22d39fd1f4e66dd3e2fc -Test manifest can be join()-ed as before, though it's silly: + $ hg log -R latesttag -r tip -T '{get(extras, "branch") % "{key}: {value}\n"}' + branch: default + $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "{key}\n"}' + hg: parse error: None is not iterable + [255] + $ hg log -R latesttag -r tip -T '{min(extras) % "{key}: {value}\n"}' + branch: default + $ hg log -R latesttag -l1 -T '{min(revset("0:9")) % "{rev}:{node|short}\n"}' + 0:ce3cec86e6c2 + $ hg log -R latesttag -l1 -T '{max(revset("0:9")) % "{rev}:{node|short}\n"}' + 9:fbc7cd862e9c + +Test manifest/get() can be join()-ed as before, though it's silly: $ hg log -R latesttag -r tip -T '{join(manifest, "")}\n' 11:2bc6e9006ce2 + $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), "")}\n' + default Test the sub function of templating for expansion: