Mercurial > hg-stable
changeset 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 | 3235afdfcf1c |
children | 47aea60d114d |
files | mercurial/templater.py mercurial/templateutil.py |
diffstat | 2 files changed, 69 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/templater.py Sat Mar 17 22:56:49 2018 +0900 +++ b/mercurial/templater.py Sat Mar 17 22:47:02 2018 +0900 @@ -44,6 +44,10 @@ mappable represents a scalar printable value, also supports % operator. + +mappinggenerator, mappinglist + represents mappings (i.e. a list of dicts), which may have default + output format. """ from __future__ import absolute_import, print_function
--- a/mercurial/templateutil.py Sat Mar 17 22:56:49 2018 +0900 +++ b/mercurial/templateutil.py Sat Mar 17 22:47:02 2018 +0900 @@ -170,6 +170,63 @@ def tovalue(self, context, mapping): return _unthunk(context, mapping, self._value) +class _mappingsequence(wrapped): + """Wrapper for sequence of template mappings + + This represents an inner template structure (i.e. a list of dicts), + which can also be rendered by the specified named/literal template. + + Template mappings may be nested. + """ + + def __init__(self, name=None, tmpl=None, sep=''): + if name is not None and tmpl is not None: + raise error.ProgrammingError('name and tmpl are mutually exclusive') + self._name = name + self._tmpl = tmpl + self._defaultsep = sep + + def join(self, context, mapping, sep): + mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context)) + if self._name: + itemiter = (context.process(self._name, m) for m in mapsiter) + elif self._tmpl: + itemiter = (context.expand(self._tmpl, m) for m in mapsiter) + else: + raise error.ParseError(_('not displayable without template')) + return joinitems(itemiter, sep) + + def show(self, context, mapping): + return self.join(context, mapping, self._defaultsep) + + def tovalue(self, context, mapping): + return list(self.itermaps(context)) + +class mappinggenerator(_mappingsequence): + """Wrapper for generator of template mappings + + The function ``make(context, *args)`` should return a generator of + mapping dicts. + """ + + def __init__(self, make, args=(), name=None, tmpl=None, sep=''): + super(mappinggenerator, self).__init__(name, tmpl, sep) + self._make = make + self._args = args + + def itermaps(self, context): + return self._make(context, *self._args) + +class mappinglist(_mappingsequence): + """Wrapper for list of template mappings""" + + def __init__(self, mappings, name=None, tmpl=None, sep=''): + super(mappinglist, self).__init__(name, tmpl, sep) + self._mappings = mappings + + def itermaps(self, context): + return iter(self._mappings) + def hybriddict(data, key='key', value='value', fmt=None, gen=None): """Wrap data to support both dict-like and string-like operations""" prefmt = pycompat.identity @@ -510,6 +567,14 @@ return (_("template filter '%s' is not compatible with keyword '%s'") % (fn, sym)) +def _iteroverlaymaps(context, origmapping, newmappings): + """Generate combined mappings from the original mapping and an iterable + of partial mappings to override the original""" + for i, nm in enumerate(newmappings): + lm = context.overlaymap(origmapping, nm) + lm['index'] = i + yield lm + def runmap(context, mapping, data): darg, targ = data d = evalrawexp(context, mapping, darg)