Mercurial > public > mercurial-scm > hg
comparison mercurial/templater.py @ 35468:32c278eb876f
templater: keep default resources per template engine (API)
This allows us to register a repo object as a resource in hgweb template,
without loosing '{repo}' symbol:
symbol('repo') -> mapping['repo'] (n/a) -> defaults['repo']
resource('repo') -> mapping['repo'] (n/a) -> resources['repo']
I'm thinking of redesigning the templatekw API to take (context, mapping)
in place of **(context._resources + mapping), but that will be a big change
and not implemented yet.
props['templ'] is ported to the resources dict as an example.
.. api::
mapping does not contain all template resources. use context.resource()
in template functions.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Thu, 21 Dec 2017 21:29:06 +0900 |
parents | d6cfa722b044 |
children | a33be093ec62 |
comparison
equal
deleted
inserted
replaced
35467:d6cfa722b044 | 35468:32c278eb876f |
---|---|
391 try: | 391 try: |
392 v = context.process(key, safemapping) | 392 v = context.process(key, safemapping) |
393 except TemplateNotFound: | 393 except TemplateNotFound: |
394 v = default | 394 v = default |
395 if callable(v): | 395 if callable(v): |
396 return v(**pycompat.strkwargs(mapping)) | 396 # TODO: templatekw functions will be updated to take (context, mapping) |
397 # pair instead of **props | |
398 props = context._resources.copy() | |
399 props.update(mapping) | |
400 return v(**props) | |
397 return v | 401 return v |
398 | 402 |
399 def buildtemplate(exp, context): | 403 def buildtemplate(exp, context): |
400 ctmpl = [compileexp(e, context, methods) for e in exp[1:]] | 404 ctmpl = [compileexp(e, context, methods) for e in exp[1:]] |
401 return (runtemplate, ctmpl) | 405 return (runtemplate, ctmpl) |
655 | 659 |
656 raw = evalstring(context, mapping, args[0]) | 660 raw = evalstring(context, mapping, args[0]) |
657 ctx = context.resource(mapping, 'ctx') | 661 ctx = context.resource(mapping, 'ctx') |
658 m = ctx.match([raw]) | 662 m = ctx.match([raw]) |
659 files = list(ctx.matches(m)) | 663 files = list(ctx.matches(m)) |
660 return templatekw.showlist("file", files, mapping) | 664 # TODO: pass (context, mapping) pair to keyword function |
665 props = context._resources.copy() | |
666 props.update(mapping) | |
667 return templatekw.showlist("file", files, props) | |
661 | 668 |
662 @templatefunc('fill(text[, width[, initialident[, hangindent]]])') | 669 @templatefunc('fill(text[, width[, initialident[, hangindent]]])') |
663 def fill(context, mapping, args): | 670 def fill(context, mapping, args): |
664 """Fill many | 671 """Fill many |
665 paragraphs with optional indentation. See the "fill" filter.""" | 672 paragraphs with optional indentation. See the "fill" filter.""" |
876 | 883 |
877 pattern = None | 884 pattern = None |
878 if len(args) == 1: | 885 if len(args) == 1: |
879 pattern = evalstring(context, mapping, args[0]) | 886 pattern = evalstring(context, mapping, args[0]) |
880 | 887 |
881 return templatekw.showlatesttags(pattern, **pycompat.strkwargs(mapping)) | 888 # TODO: pass (context, mapping) pair to keyword function |
889 props = context._resources.copy() | |
890 props.update(mapping) | |
891 return templatekw.showlatesttags(pattern, **pycompat.strkwargs(props)) | |
882 | 892 |
883 @templatefunc('localdate(date[, tz])') | 893 @templatefunc('localdate(date[, tz])') |
884 def localdate(context, mapping, args): | 894 def localdate(context, mapping, args): |
885 """Converts a date to the specified timezone. | 895 """Converts a date to the specified timezone. |
886 The default is local date.""" | 896 The default is local date.""" |
1060 else: | 1070 else: |
1061 revs = query(raw) | 1071 revs = query(raw) |
1062 revs = list(revs) | 1072 revs = list(revs) |
1063 revsetcache[raw] = revs | 1073 revsetcache[raw] = revs |
1064 | 1074 |
1075 # TODO: pass (context, mapping) pair to keyword function | |
1076 props = context._resources.copy() | |
1077 props.update(mapping) | |
1065 return templatekw.showrevslist("revision", revs, | 1078 return templatekw.showrevslist("revision", revs, |
1066 **pycompat.strkwargs(mapping)) | 1079 **pycompat.strkwargs(props)) |
1067 | 1080 |
1068 @templatefunc('rstdoc(text, style)') | 1081 @templatefunc('rstdoc(text, style)') |
1069 def rstdoc(context, mapping, args): | 1082 def rstdoc(context, mapping, args): |
1070 """Format reStructuredText.""" | 1083 """Format reStructuredText.""" |
1071 if len(args) != 2: | 1084 if len(args) != 2: |
1288 {key%format}. | 1301 {key%format}. |
1289 | 1302 |
1290 filter uses function to transform value. syntax is | 1303 filter uses function to transform value. syntax is |
1291 {key|filter1|filter2|...}.''' | 1304 {key|filter1|filter2|...}.''' |
1292 | 1305 |
1293 def __init__(self, loader, filters=None, defaults=None, aliases=()): | 1306 def __init__(self, loader, filters=None, defaults=None, resources=None, |
1307 aliases=()): | |
1294 self._loader = loader | 1308 self._loader = loader |
1295 if filters is None: | 1309 if filters is None: |
1296 filters = {} | 1310 filters = {} |
1297 self._filters = filters | 1311 self._filters = filters |
1298 if defaults is None: | 1312 if defaults is None: |
1299 defaults = {} | 1313 defaults = {} |
1314 if resources is None: | |
1315 resources = {} | |
1300 self._defaults = defaults | 1316 self._defaults = defaults |
1317 self._resources = resources | |
1301 self._aliasmap = _aliasrules.buildmap(aliases) | 1318 self._aliasmap = _aliasrules.buildmap(aliases) |
1302 self._cache = {} # key: (func, data) | 1319 self._cache = {} # key: (func, data) |
1303 | 1320 |
1304 def symbol(self, mapping, key): | 1321 def symbol(self, mapping, key): |
1305 """Resolve symbol to value or function; None if nothing found""" | 1322 """Resolve symbol to value or function; None if nothing found""" |
1309 return v | 1326 return v |
1310 | 1327 |
1311 def resource(self, mapping, key): | 1328 def resource(self, mapping, key): |
1312 """Return internal data (e.g. cache) used for keyword/function | 1329 """Return internal data (e.g. cache) used for keyword/function |
1313 evaluation""" | 1330 evaluation""" |
1314 return mapping[key] | 1331 v = mapping.get(key) |
1332 if v is None: | |
1333 v = self._resources.get(key) | |
1334 if v is None: | |
1335 raise KeyError | |
1336 return v | |
1315 | 1337 |
1316 def _load(self, t): | 1338 def _load(self, t): |
1317 '''load, parse, and cache a template''' | 1339 '''load, parse, and cache a template''' |
1318 if t not in self._cache: | 1340 if t not in self._cache: |
1319 # put poison to cut recursion while compiling 't' | 1341 # put poison to cut recursion while compiling 't' |
1404 class TemplateNotFound(error.Abort): | 1426 class TemplateNotFound(error.Abort): |
1405 pass | 1427 pass |
1406 | 1428 |
1407 class templater(object): | 1429 class templater(object): |
1408 | 1430 |
1409 def __init__(self, filters=None, defaults=None, cache=None, aliases=(), | 1431 def __init__(self, filters=None, defaults=None, resources=None, |
1410 minchunk=1024, maxchunk=65536): | 1432 cache=None, aliases=(), minchunk=1024, maxchunk=65536): |
1411 '''set up template engine. | 1433 '''set up template engine. |
1412 filters is dict of functions. each transforms a value into another. | 1434 filters is dict of functions. each transforms a value into another. |
1413 defaults is dict of default map definitions. | 1435 defaults is dict of default map definitions. |
1436 resources is dict of internal data (e.g. cache), which are inaccessible | |
1437 from user template. | |
1414 aliases is list of alias (name, replacement) pairs. | 1438 aliases is list of alias (name, replacement) pairs. |
1415 ''' | 1439 ''' |
1416 if filters is None: | 1440 if filters is None: |
1417 filters = {} | 1441 filters = {} |
1418 if defaults is None: | 1442 if defaults is None: |
1419 defaults = {} | 1443 defaults = {} |
1444 if resources is None: | |
1445 resources = {} | |
1420 if cache is None: | 1446 if cache is None: |
1421 cache = {} | 1447 cache = {} |
1422 self.cache = cache.copy() | 1448 self.cache = cache.copy() |
1423 self.map = {} | 1449 self.map = {} |
1424 self.filters = templatefilters.filters.copy() | 1450 self.filters = templatefilters.filters.copy() |
1425 self.filters.update(filters) | 1451 self.filters.update(filters) |
1426 self.defaults = defaults | 1452 self.defaults = defaults |
1453 self._resources = {'templ': self} | |
1454 self._resources.update(resources) | |
1427 self._aliases = aliases | 1455 self._aliases = aliases |
1428 self.minchunk, self.maxchunk = minchunk, maxchunk | 1456 self.minchunk, self.maxchunk = minchunk, maxchunk |
1429 self.ecache = {} | 1457 self.ecache = {} |
1430 | 1458 |
1431 @classmethod | 1459 @classmethod |
1432 def frommapfile(cls, mapfile, filters=None, defaults=None, cache=None, | 1460 def frommapfile(cls, mapfile, filters=None, defaults=None, resources=None, |
1433 minchunk=1024, maxchunk=65536): | 1461 cache=None, minchunk=1024, maxchunk=65536): |
1434 """Create templater from the specified map file""" | 1462 """Create templater from the specified map file""" |
1435 t = cls(filters, defaults, cache, [], minchunk, maxchunk) | 1463 t = cls(filters, defaults, resources, cache, [], minchunk, maxchunk) |
1436 cache, tmap, aliases = _readmapfile(mapfile) | 1464 cache, tmap, aliases = _readmapfile(mapfile) |
1437 t.cache.update(cache) | 1465 t.cache.update(cache) |
1438 t.map = tmap | 1466 t.map = tmap |
1439 t._aliases = aliases | 1467 t._aliases = aliases |
1440 return t | 1468 return t |
1467 try: | 1495 try: |
1468 ecls = engines[ttype] | 1496 ecls = engines[ttype] |
1469 except KeyError: | 1497 except KeyError: |
1470 raise error.Abort(_('invalid template engine: %s') % ttype) | 1498 raise error.Abort(_('invalid template engine: %s') % ttype) |
1471 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults, | 1499 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults, |
1472 self._aliases) | 1500 self._resources, self._aliases) |
1473 proc = self.ecache[ttype] | 1501 proc = self.ecache[ttype] |
1474 | 1502 |
1475 stream = proc.process(t, mapping) | 1503 stream = proc.process(t, mapping) |
1476 if self.minchunk: | 1504 if self.minchunk: |
1477 stream = util.increasingchunks(stream, min=self.minchunk, | 1505 stream = util.increasingchunks(stream, min=self.minchunk, |