348 baseformatter.__init__(self, ui, topic, opts, _templateconverter) |
348 baseformatter.__init__(self, ui, topic, opts, _templateconverter) |
349 self._out = out |
349 self._out = out |
350 spec = lookuptemplate(ui, topic, opts.get('template', '')) |
350 spec = lookuptemplate(ui, topic, opts.get('template', '')) |
351 self._tref = spec.ref |
351 self._tref = spec.ref |
352 self._t = loadtemplater(ui, spec, cache=templatekw.defaulttempl) |
352 self._t = loadtemplater(ui, spec, cache=templatekw.defaulttempl) |
|
353 self._parts = templatepartsmap(spec, self._t, |
|
354 ['docheader', 'docfooter']) |
353 self._counter = itertools.count() |
355 self._counter = itertools.count() |
354 self._cache = {} # for templatekw/funcs to store reusable data |
356 self._cache = {} # for templatekw/funcs to store reusable data |
|
357 self._renderitem('docheader', {}) |
|
358 |
355 def context(self, **ctxs): |
359 def context(self, **ctxs): |
356 '''insert context objects to be used to render template keywords''' |
360 '''insert context objects to be used to render template keywords''' |
357 ctxs = pycompat.byteskwargs(ctxs) |
361 ctxs = pycompat.byteskwargs(ctxs) |
358 assert all(k == 'ctx' for k in ctxs) |
362 assert all(k == 'ctx' for k in ctxs) |
359 self._item.update(ctxs) |
363 self._item.update(ctxs) |
361 def _showitem(self): |
365 def _showitem(self): |
362 item = self._item.copy() |
366 item = self._item.copy() |
363 item['index'] = next(self._counter) |
367 item['index'] = next(self._counter) |
364 self._renderitem(self._tref, item) |
368 self._renderitem(self._tref, item) |
365 |
369 |
366 def _renderitem(self, ref, item): |
370 def _renderitem(self, part, item): |
|
371 if part not in self._parts: |
|
372 return |
|
373 ref = self._parts[part] |
|
374 |
367 # TODO: add support for filectx. probably each template keyword or |
375 # TODO: add support for filectx. probably each template keyword or |
368 # function will have to declare dependent resources. e.g. |
376 # function will have to declare dependent resources. e.g. |
369 # @templatekeyword(..., requires=('ctx',)) |
377 # @templatekeyword(..., requires=('ctx',)) |
370 props = {} |
378 props = {} |
371 if 'ctx' in item: |
379 if 'ctx' in item: |
379 props['revcache'] = {} |
387 props['revcache'] = {} |
380 props = pycompat.strkwargs(props) |
388 props = pycompat.strkwargs(props) |
381 g = self._t(ref, ui=self._ui, cache=self._cache, **props) |
389 g = self._t(ref, ui=self._ui, cache=self._cache, **props) |
382 self._out.write(templater.stringify(g)) |
390 self._out.write(templater.stringify(g)) |
383 |
391 |
|
392 def end(self): |
|
393 baseformatter.end(self) |
|
394 self._renderitem('docfooter', {}) |
|
395 |
384 templatespec = collections.namedtuple(r'templatespec', |
396 templatespec = collections.namedtuple(r'templatespec', |
385 r'ref tmpl mapfile') |
397 r'ref tmpl mapfile') |
386 |
398 |
387 def lookuptemplate(ui, topic, tmpl): |
399 def lookuptemplate(ui, topic, tmpl): |
388 """Find the template matching the given -T/--template spec 'tmpl' |
400 """Find the template matching the given -T/--template spec 'tmpl' |
431 tmpl = f.read() |
443 tmpl = f.read() |
432 return templatespec('', tmpl, None) |
444 return templatespec('', tmpl, None) |
433 |
445 |
434 # constant string? |
446 # constant string? |
435 return templatespec('', tmpl, None) |
447 return templatespec('', tmpl, None) |
|
448 |
|
449 def templatepartsmap(spec, t, partnames): |
|
450 """Create a mapping of {part: ref}""" |
|
451 partsmap = {spec.ref: spec.ref} # initial ref must exist in t |
|
452 if spec.mapfile: |
|
453 partsmap.update((p, p) for p in partnames if p in t) |
|
454 return partsmap |
436 |
455 |
437 def loadtemplater(ui, spec, cache=None): |
456 def loadtemplater(ui, spec, cache=None): |
438 """Create a templater from either a literal template or loading from |
457 """Create a templater from either a literal template or loading from |
439 a map file""" |
458 a map file""" |
440 assert not (spec.tmpl and spec.mapfile) |
459 assert not (spec.tmpl and spec.mapfile) |