##// END OF EJS Templates
templatekw: add 'requires' flag to switch to exception-safe interface...
Yuya Nishihara -
r36463:e8d37838 default
parent child Browse files
Show More
@@ -383,9 +383,7 b' class templateformatter(baseformatter):'
383 return
383 return
384 ref = self._parts[part]
384 ref = self._parts[part]
385
385
386 # TODO: add support for filectx. probably each template keyword or
386 # TODO: add support for filectx
387 # function will have to declare dependent resources. e.g.
388 # @templatekeyword(..., requires=('ctx',))
389 props = {}
387 props = {}
390 # explicitly-defined fields precede templatekw
388 # explicitly-defined fields precede templatekw
391 props.update(item)
389 props.update(item)
@@ -283,6 +283,14 b' class templatekeyword(_templateregistrar'
283
283
284 templatekeyword = registrar.templatekeyword()
284 templatekeyword = registrar.templatekeyword()
285
285
286 # new API (since Mercurial 4.6)
287 @templatekeyword('mykeyword', requires={'repo', 'ctx'})
288 def mykeywordfunc(context, mapping):
289 '''Explanation of this template keyword ....
290 '''
291 pass
292
293 # old API
286 @templatekeyword('mykeyword')
294 @templatekeyword('mykeyword')
287 def mykeywordfunc(repo, ctx, templ, cache, revcache, **args):
295 def mykeywordfunc(repo, ctx, templ, cache, revcache, **args):
288 '''Explanation of this template keyword ....
296 '''Explanation of this template keyword ....
@@ -291,6 +299,11 b' class templatekeyword(_templateregistrar'
291
299
292 The first string argument is used also in online help.
300 The first string argument is used also in online help.
293
301
302 Optional argument 'requires' should be a collection of resource names
303 which the template keyword depends on. This also serves as a flag to
304 switch to the new API. If 'requires' is unspecified, all template
305 keywords and resources are expanded to the function arguments.
306
294 'templatekeyword' instance in example above can be used to
307 'templatekeyword' instance in example above can be used to
295 decorate multiple functions.
308 decorate multiple functions.
296
309
@@ -301,6 +314,9 b' class templatekeyword(_templateregistrar'
301 Otherwise, explicit 'templatekw.loadkeyword()' is needed.
314 Otherwise, explicit 'templatekw.loadkeyword()' is needed.
302 """
315 """
303
316
317 def _extrasetup(self, name, func, requires=None):
318 func._requires = requires
319
304 class templatefilter(_templateregistrarbase):
320 class templatefilter(_templateregistrarbase):
305 """Decorator to register template filer
321 """Decorator to register template filer
306
322
@@ -341,21 +341,14 b' defaulttempl = {'
341 # filecopy is preserved for compatibility reasons
341 # filecopy is preserved for compatibility reasons
342 defaulttempl['filecopy'] = defaulttempl['file_copy']
342 defaulttempl['filecopy'] = defaulttempl['file_copy']
343
343
344 # keywords are callables like:
344 # keywords are callables (see registrar.templatekeyword for details)
345 # fn(repo, ctx, templ, cache, revcache, **args)
346 # with:
347 # repo - current repository instance
348 # ctx - the changectx being displayed
349 # templ - the templater instance
350 # cache - a cache dictionary for the whole templater run
351 # revcache - a cache dictionary for the current revision
352 keywords = {}
345 keywords = {}
353
354 templatekeyword = registrar.templatekeyword(keywords)
346 templatekeyword = registrar.templatekeyword(keywords)
355
347
356 @templatekeyword('author')
348 @templatekeyword('author', requires={'ctx'})
357 def showauthor(repo, ctx, templ, **args):
349 def showauthor(context, mapping):
358 """String. The unmodified author of the changeset."""
350 """String. The unmodified author of the changeset."""
351 ctx = context.resource(mapping, 'ctx')
359 return ctx.user()
352 return ctx.user()
360
353
361 @templatekeyword('bisect')
354 @templatekeyword('bisect')
@@ -436,12 +436,18 b' def runsymbol(context, mapping, key, def'
436 v = context.process(key, safemapping)
436 v = context.process(key, safemapping)
437 except TemplateNotFound:
437 except TemplateNotFound:
438 v = default
438 v = default
439 if callable(v):
439 if callable(v) and getattr(v, '_requires', None) is None:
440 # TODO: templatekw functions will be updated to take (context, mapping)
440 # old templatekw: expand all keywords and resources
441 # pair instead of **props
442 props = context._resources.copy()
441 props = context._resources.copy()
443 props.update(mapping)
442 props.update(mapping)
444 return v(**pycompat.strkwargs(props))
443 return v(**pycompat.strkwargs(props))
444 if callable(v):
445 # new templatekw
446 try:
447 return v(context, mapping)
448 except ResourceUnavailable:
449 # unsupported keyword is mapped to empty just like unknown keyword
450 return None
445 return v
451 return v
446
452
447 def buildtemplate(exp, context):
453 def buildtemplate(exp, context):
@@ -214,6 +214,8 b' Never crash on internal resource not ava'
214 abort: template resource not available: ctx
214 abort: template resource not available: ctx
215 [255]
215 [255]
216
216
217 $ hg config -T '{author}'
218
217 Quoting for ui.logtemplate
219 Quoting for ui.logtemplate
218
220
219 $ hg tip --config "ui.logtemplate={rev}\n"
221 $ hg tip --config "ui.logtemplate={rev}\n"
@@ -9,6 +9,15 b''
9 > self._defaults = defaults
9 > self._defaults = defaults
10 > self._resources = resources
10 > self._resources = resources
11 >
11 >
12 > def symbol(self, mapping, key):
13 > return mapping[key]
14 >
15 > def resource(self, mapping, key):
16 > v = self._resources[key]
17 > if v is None:
18 > v = mapping[key]
19 > return v
20 >
12 > def process(self, t, map):
21 > def process(self, t, map):
13 > tmpl = self.loader(t)
22 > tmpl = self.loader(t)
14 > props = self._defaults.copy()
23 > props = self._defaults.copy()
@@ -16,10 +25,12 b''
16 > for k, v in props.items():
25 > for k, v in props.items():
17 > if k in ('templ', 'ctx', 'repo', 'revcache', 'cache', 'troubles'):
26 > if k in ('templ', 'ctx', 'repo', 'revcache', 'cache', 'troubles'):
18 > continue
27 > continue
19 > if hasattr(v, '__call__'):
28 > if callable(v) and getattr(v, '_requires', None) is None:
20 > props = self._resources.copy()
29 > props = self._resources.copy()
21 > props.update(map)
30 > props.update(map)
22 > v = v(**props)
31 > v = v(**props)
32 > elif callable(v):
33 > v = v(self, props)
23 > v = templater.stringify(v)
34 > v = templater.stringify(v)
24 > tmpl = tmpl.replace('{{%s}}' % k, v)
35 > tmpl = tmpl.replace('{{%s}}' % k, v)
25 > yield tmpl
36 > yield tmpl
General Comments 0
You need to be logged in to leave comments. Login now