Mercurial > public > mercurial-scm > hg
comparison mercurial/templateutil.py @ 37399:0b64416224d9
templater: add class representing a nested mappings
The mappinggenerator class is necessary to fix hgweb bugs without BC. The
mappinglist is for nested formatter items. They are similar, so factored
out the base class. The mappinglist could be implemented by using the
mappinggenerator, but we'll probably need a direct access to the raw list,
so they are implemented as separate classes.
Note that tovalue() isn't conforming to the spec yet in that it may return
a list of dicts containing unprintable resources. This problem will be
fixed later.
Tests will be added by subsequent patches.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sat, 17 Mar 2018 22:47:02 +0900 |
parents | 676664592313 |
children | 7c902a8345ef |
comparison
equal
deleted
inserted
replaced
37398:3235afdfcf1c | 37399:0b64416224d9 |
---|---|
167 return gen() | 167 return gen() |
168 return gen | 168 return gen |
169 | 169 |
170 def tovalue(self, context, mapping): | 170 def tovalue(self, context, mapping): |
171 return _unthunk(context, mapping, self._value) | 171 return _unthunk(context, mapping, self._value) |
172 | |
173 class _mappingsequence(wrapped): | |
174 """Wrapper for sequence of template mappings | |
175 | |
176 This represents an inner template structure (i.e. a list of dicts), | |
177 which can also be rendered by the specified named/literal template. | |
178 | |
179 Template mappings may be nested. | |
180 """ | |
181 | |
182 def __init__(self, name=None, tmpl=None, sep=''): | |
183 if name is not None and tmpl is not None: | |
184 raise error.ProgrammingError('name and tmpl are mutually exclusive') | |
185 self._name = name | |
186 self._tmpl = tmpl | |
187 self._defaultsep = sep | |
188 | |
189 def join(self, context, mapping, sep): | |
190 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context)) | |
191 if self._name: | |
192 itemiter = (context.process(self._name, m) for m in mapsiter) | |
193 elif self._tmpl: | |
194 itemiter = (context.expand(self._tmpl, m) for m in mapsiter) | |
195 else: | |
196 raise error.ParseError(_('not displayable without template')) | |
197 return joinitems(itemiter, sep) | |
198 | |
199 def show(self, context, mapping): | |
200 return self.join(context, mapping, self._defaultsep) | |
201 | |
202 def tovalue(self, context, mapping): | |
203 return list(self.itermaps(context)) | |
204 | |
205 class mappinggenerator(_mappingsequence): | |
206 """Wrapper for generator of template mappings | |
207 | |
208 The function ``make(context, *args)`` should return a generator of | |
209 mapping dicts. | |
210 """ | |
211 | |
212 def __init__(self, make, args=(), name=None, tmpl=None, sep=''): | |
213 super(mappinggenerator, self).__init__(name, tmpl, sep) | |
214 self._make = make | |
215 self._args = args | |
216 | |
217 def itermaps(self, context): | |
218 return self._make(context, *self._args) | |
219 | |
220 class mappinglist(_mappingsequence): | |
221 """Wrapper for list of template mappings""" | |
222 | |
223 def __init__(self, mappings, name=None, tmpl=None, sep=''): | |
224 super(mappinglist, self).__init__(name, tmpl, sep) | |
225 self._mappings = mappings | |
226 | |
227 def itermaps(self, context): | |
228 return iter(self._mappings) | |
172 | 229 |
173 def hybriddict(data, key='key', value='value', fmt=None, gen=None): | 230 def hybriddict(data, key='key', value='value', fmt=None, gen=None): |
174 """Wrap data to support both dict-like and string-like operations""" | 231 """Wrap data to support both dict-like and string-like operations""" |
175 prefmt = pycompat.identity | 232 prefmt = pycompat.identity |
176 if fmt is None: | 233 if fmt is None: |
508 if not sym: | 565 if not sym: |
509 return _("incompatible use of template filter '%s'") % fn | 566 return _("incompatible use of template filter '%s'") % fn |
510 return (_("template filter '%s' is not compatible with keyword '%s'") | 567 return (_("template filter '%s' is not compatible with keyword '%s'") |
511 % (fn, sym)) | 568 % (fn, sym)) |
512 | 569 |
570 def _iteroverlaymaps(context, origmapping, newmappings): | |
571 """Generate combined mappings from the original mapping and an iterable | |
572 of partial mappings to override the original""" | |
573 for i, nm in enumerate(newmappings): | |
574 lm = context.overlaymap(origmapping, nm) | |
575 lm['index'] = i | |
576 yield lm | |
577 | |
513 def runmap(context, mapping, data): | 578 def runmap(context, mapping, data): |
514 darg, targ = data | 579 darg, targ = data |
515 d = evalrawexp(context, mapping, darg) | 580 d = evalrawexp(context, mapping, darg) |
516 if isinstance(d, wrapped): | 581 if isinstance(d, wrapped): |
517 diter = d.itermaps(context) | 582 diter = d.itermaps(context) |