Mercurial > public > mercurial-scm > hg
comparison mercurial/templatekw.py @ 34425:12bfecd0ffe6
formatter: fix default list/dict generator to be evaluated more than once
Before, _hybrid.gen must be a generator which could be consumed only once.
It was okay in templatekw.py since template keywords are functions which
create temporary hybrid objects, but the formatter doesn't work in that way.
To work around the issue, this patch makes _hybrid.gen optionally be a
function returning a generator.
Thanks to Pulkit for finding this issue.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 01 Oct 2017 08:37:04 +0100 |
parents | 89aec1834a86 |
children | b3073e175c17 |
comparison
equal
deleted
inserted
replaced
34424:e416819d9ebb | 34425:12bfecd0ffe6 |
---|---|
37 - "{files|json}" | 37 - "{files|json}" |
38 """ | 38 """ |
39 | 39 |
40 def __init__(self, gen, values, makemap, joinfmt): | 40 def __init__(self, gen, values, makemap, joinfmt): |
41 if gen is not None: | 41 if gen is not None: |
42 self.gen = gen | 42 self.gen = gen # generator or function returning generator |
43 self._values = values | 43 self._values = values |
44 self._makemap = makemap | 44 self._makemap = makemap |
45 self.joinfmt = joinfmt | 45 self.joinfmt = joinfmt |
46 @util.propertycache | |
47 def gen(self): | 46 def gen(self): |
48 return self._defaultgen() | 47 """Default generator to stringify this as {join(self, ' ')}""" |
49 def _defaultgen(self): | |
50 """Generator to stringify this as {join(self, ' ')}""" | |
51 for i, x in enumerate(self._values): | 48 for i, x in enumerate(self._values): |
52 if i > 0: | 49 if i > 0: |
53 yield ' ' | 50 yield ' ' |
54 yield self.joinfmt(x) | 51 yield self.joinfmt(x) |
55 def itermaps(self): | 52 def itermaps(self): |
102 return _hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % x) | 99 return _hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % x) |
103 | 100 |
104 def unwraphybrid(thing): | 101 def unwraphybrid(thing): |
105 """Return an object which can be stringified possibly by using a legacy | 102 """Return an object which can be stringified possibly by using a legacy |
106 template""" | 103 template""" |
107 if not util.safehasattr(thing, 'gen'): | 104 gen = getattr(thing, 'gen', None) |
105 if gen is None: | |
108 return thing | 106 return thing |
109 return thing.gen | 107 if callable(gen): |
108 return gen() | |
109 return gen | |
110 | 110 |
111 def unwrapvalue(thing): | 111 def unwrapvalue(thing): |
112 """Move the inner value object out of the wrapper""" | 112 """Move the inner value object out of the wrapper""" |
113 if not util.safehasattr(thing, '_value'): | 113 if not util.safehasattr(thing, '_value'): |
114 return thing | 114 return thing |
683 data.append(h) | 683 data.append(h) |
684 | 684 |
685 # Format the successorssets | 685 # Format the successorssets |
686 def render(d): | 686 def render(d): |
687 t = [] | 687 t = [] |
688 for i in d.gen: | 688 for i in d.gen(): |
689 t.append(i) | 689 t.append(i) |
690 return "".join(t) | 690 return "".join(t) |
691 | 691 |
692 def gen(data): | 692 def gen(data): |
693 yield "; ".join(render(d) for d in data) | 693 yield "; ".join(render(d) for d in data) |