templater: factor out function to create mapping dict for nested evaluation
overlaymap() is the hook point to drop mapping items conflicting with the
default keywords which have to be re-evaluated with new 'ctx' resource.
--- a/mercurial/templatekw.py Thu Mar 15 20:43:39 2018 +0900
+++ b/mercurial/templatekw.py Thu Mar 15 21:22:52 2018 +0900
@@ -449,8 +449,8 @@
@templatekeyword('changessincelatesttag', requires={'repo', 'ctx', 'cache'})
def showchangessincelatesttag(context, mapping):
"""Integer. All ancestors not in the latest tag."""
- mapping = mapping.copy()
- mapping['tag'] = getlatesttags(context, mapping)[2][0]
+ tag = getlatesttags(context, mapping)[2][0]
+ mapping = context.overlaymap(mapping, {'tag': tag})
return _showchangessincetag(context, mapping)
def _showchangessincetag(context, mapping):
@@ -480,8 +480,7 @@
return
mrev = repo.manifestlog._revlog.rev(mnode)
mhex = hex(mnode)
- mapping = mapping.copy()
- mapping.update({'rev': mrev, 'node': mhex})
+ mapping = context.overlaymap(mapping, {'rev': mrev, 'node': mhex})
f = context.process('manifest', mapping)
# TODO: perhaps 'ctx' should be dropped from mapping because manifest
# rev and node are completely different from changeset's.
--- a/mercurial/templater.py Thu Mar 15 20:43:39 2018 +0900
+++ b/mercurial/templater.py Thu Mar 15 21:22:52 2018 +0900
@@ -613,6 +613,13 @@
self._aliasmap = _aliasrules.buildmap(aliases)
self._cache = {} # key: (func, data)
+ def overlaymap(self, origmapping, newmapping):
+ """Create combined mapping from the original mapping and partial
+ mapping to override the original"""
+ mapping = origmapping.copy()
+ mapping.update(newmapping)
+ return mapping
+
def symbol(self, mapping, key):
"""Resolve symbol to value or function; None if nothing found"""
v = None
--- a/mercurial/templateutil.py Thu Mar 15 20:43:39 2018 +0900
+++ b/mercurial/templateutil.py Thu Mar 15 21:22:52 2018 +0900
@@ -202,8 +202,8 @@
startname = 'start_' + plural
if context.preload(startname):
yield context.process(startname, mapping)
- vmapping = mapping.copy()
def one(v, tag=name):
+ vmapping = {}
try:
vmapping.update(v)
# Python 2 raises ValueError if the type of v is wrong. Python
@@ -216,6 +216,7 @@
vmapping[a] = b
except (TypeError, ValueError):
vmapping[name] = v
+ vmapping = context.overlaymap(mapping, vmapping)
return context.process(tag, vmapping)
lastname = 'last_' + name
if context.preload(lastname):
@@ -399,10 +400,9 @@
raise error.ParseError(_("%r is not iterable") % d)
for i, v in enumerate(diter):
- lm = mapping.copy()
- lm['index'] = i
if isinstance(v, dict):
- lm.update(v)
+ lm = context.overlaymap(mapping, v)
+ lm['index'] = i
lm['originalnode'] = mapping.get('node')
yield evalrawexp(context, lm, targ)
else:
@@ -415,8 +415,7 @@
darg, memb = data
d = evalrawexp(context, mapping, darg)
if util.safehasattr(d, 'tomap'):
- lm = mapping.copy()
- lm.update(d.tomap())
+ lm = context.overlaymap(mapping, d.tomap())
return runsymbol(context, lm, memb)
if util.safehasattr(d, 'get'):
return getdictitem(d, memb)