comparison mercurial/templateutil.py @ 37499:75c13343cf38

templater: wrap result of '%' operation so it never looks like a thunk This fixes min/max()/json() of map result. Before, it was taken as a lazy byte string and stringified by evalfuncarg().
author Yuya Nishihara <yuya@tcha.org>
date Sun, 18 Mar 2018 23:36:52 +0900
parents da8e9ecac4a4
children 40c7347f6848
comparison
equal deleted inserted replaced
37498:aacfca6f9767 37499:75c13343cf38
224 super(mappinglist, self).__init__(name, tmpl, sep) 224 super(mappinglist, self).__init__(name, tmpl, sep)
225 self._mappings = mappings 225 self._mappings = mappings
226 226
227 def itermaps(self, context): 227 def itermaps(self, context):
228 return iter(self._mappings) 228 return iter(self._mappings)
229
230 class mappedgenerator(wrapped):
231 """Wrapper for generator of strings which acts as a list
232
233 The function ``make(context, *args)`` should return a generator of
234 byte strings, or a generator of (possibly nested) generators of byte
235 strings (i.e. a generator for a list of byte strings.)
236 """
237
238 def __init__(self, make, args=()):
239 self._make = make
240 self._args = args
241
242 def _gen(self, context):
243 return self._make(context, *self._args)
244
245 def itermaps(self, context):
246 raise error.ParseError(_('list of strings is not mappable'))
247
248 def join(self, context, mapping, sep):
249 return joinitems(self._gen(context), sep)
250
251 def show(self, context, mapping):
252 return self.join(context, mapping, '')
253
254 def tovalue(self, context, mapping):
255 return [stringify(context, mapping, x) for x in self._gen(context)]
229 256
230 def hybriddict(data, key='key', value='value', fmt=None, gen=None): 257 def hybriddict(data, key='key', value='value', fmt=None, gen=None):
231 """Wrap data to support both dict-like and string-like operations""" 258 """Wrap data to support both dict-like and string-like operations"""
232 prefmt = pycompat.identity 259 prefmt = pycompat.identity
233 if fmt is None: 260 if fmt is None:
587 for i, nm in enumerate(newmappings): 614 for i, nm in enumerate(newmappings):
588 lm = context.overlaymap(origmapping, nm) 615 lm = context.overlaymap(origmapping, nm)
589 lm['index'] = i 616 lm['index'] = i
590 yield lm 617 yield lm
591 618
619 def _applymap(context, mapping, diter, targ):
620 for lm in _iteroverlaymaps(context, mapping, diter):
621 yield evalrawexp(context, lm, targ)
622
592 def runmap(context, mapping, data): 623 def runmap(context, mapping, data):
593 darg, targ = data 624 darg, targ = data
594 d = evalrawexp(context, mapping, darg) 625 d = evalrawexp(context, mapping, darg)
595 # TODO: a generator should be rejected because it is a thunk of lazy 626 # TODO: a generator should be rejected because it is a thunk of lazy
596 # string, but we can't because hgweb abuses generator as a keyword 627 # string, but we can't because hgweb abuses generator as a keyword
597 # that returns a list of dicts. 628 # that returns a list of dicts.
629 # TODO: drop _checkeditermaps() and pass 'd' to mappedgenerator so it
630 # can be restarted.
598 if isinstance(d, wrapped): 631 if isinstance(d, wrapped):
599 diter = d.itermaps(context) 632 diter = d.itermaps(context)
600 else: 633 else:
601 diter = _checkeditermaps(darg, d) 634 diter = _checkeditermaps(darg, d)
602 for lm in _iteroverlaymaps(context, mapping, diter): 635 return mappedgenerator(_applymap, args=(mapping, diter, targ))
603 yield evalrawexp(context, lm, targ)
604 636
605 def runmember(context, mapping, data): 637 def runmember(context, mapping, data):
606 darg, memb = data 638 darg, memb = data
607 d = evalrawexp(context, mapping, darg) 639 d = evalrawexp(context, mapping, darg)
608 if util.safehasattr(d, 'tomap'): 640 if util.safehasattr(d, 'tomap'):