mercurial/templateutil.py
changeset 37273 83e1bbd48991
parent 37272 7d3bc1d4e871
child 37275 8c84dc8264dc
equal deleted inserted replaced
37272:7d3bc1d4e871 37273:83e1bbd48991
     5 # This software may be used and distributed according to the terms of the
     5 # This software may be used and distributed according to the terms of the
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import
     8 from __future__ import absolute_import
     9 
     9 
       
    10 import abc
    10 import types
    11 import types
    11 
    12 
    12 from .i18n import _
    13 from .i18n import _
    13 from . import (
    14 from . import (
    14     error,
    15     error,
    24     pass
    25     pass
    25 
    26 
    26 class TemplateNotFound(error.Abort):
    27 class TemplateNotFound(error.Abort):
    27     pass
    28     pass
    28 
    29 
       
    30 class wrapped(object):
       
    31     """Object requiring extra conversion prior to displaying or processing
       
    32     as value"""
       
    33 
       
    34     __metaclass__ = abc.ABCMeta
       
    35 
       
    36     @abc.abstractmethod
       
    37     def show(self, context, mapping):
       
    38         """Return a bytes or (possibly nested) generator of bytes representing
       
    39         the underlying object
       
    40 
       
    41         A pre-configured template may be rendered if the underlying object is
       
    42         not printable.
       
    43         """
       
    44 
    29 # stub for representing a date type; may be a real date type that can
    45 # stub for representing a date type; may be a real date type that can
    30 # provide a readable string value
    46 # provide a readable string value
    31 class date(object):
    47 class date(object):
    32     pass
    48     pass
    33 
    49 
    34 class hybrid(object):
    50 class hybrid(wrapped):
    35     """Wrapper for list or dict to support legacy template
    51     """Wrapper for list or dict to support legacy template
    36 
    52 
    37     This class allows us to handle both:
    53     This class allows us to handle both:
    38     - "{files}" (legacy command-line-specific list hack) and
    54     - "{files}" (legacy command-line-specific list hack) and
    39     - "{files % '{file}\n'}" (hgweb-style with inlining and function support)
    55     - "{files % '{file}\n'}" (hgweb-style with inlining and function support)
    58             yield self.joinfmt(x)
    74             yield self.joinfmt(x)
    59     def itermaps(self):
    75     def itermaps(self):
    60         makemap = self._makemap
    76         makemap = self._makemap
    61         for x in self._values:
    77         for x in self._values:
    62             yield makemap(x)
    78             yield makemap(x)
       
    79 
       
    80     def show(self, context, mapping):
       
    81         # TODO: switch gen to (context, mapping) API?
       
    82         gen = self.gen
       
    83         if callable(gen):
       
    84             return gen()
       
    85         return gen
       
    86 
    63     def __contains__(self, x):
    87     def __contains__(self, x):
    64         return x in self._values
    88         return x in self._values
    65     def __getitem__(self, key):
    89     def __getitem__(self, key):
    66         return self._values[key]
    90         return self._values[key]
    67     def __len__(self):
    91     def __len__(self):
    72         if name not in (r'get', r'items', r'iteritems', r'iterkeys',
    96         if name not in (r'get', r'items', r'iteritems', r'iterkeys',
    73                         r'itervalues', r'keys', r'values'):
    97                         r'itervalues', r'keys', r'values'):
    74             raise AttributeError(name)
    98             raise AttributeError(name)
    75         return getattr(self._values, name)
    99         return getattr(self._values, name)
    76 
   100 
    77 class mappable(object):
   101 class mappable(wrapped):
    78     """Wrapper for non-list/dict object to support map operation
   102     """Wrapper for non-list/dict object to support map operation
    79 
   103 
    80     This class allows us to handle both:
   104     This class allows us to handle both:
    81     - "{manifest}"
   105     - "{manifest}"
    82     - "{manifest % '{rev}:{node}'}"
   106     - "{manifest % '{rev}:{node}'}"
   100     def tomap(self):
   124     def tomap(self):
   101         return self._makemap(self._key)
   125         return self._makemap(self._key)
   102 
   126 
   103     def itermaps(self):
   127     def itermaps(self):
   104         yield self.tomap()
   128         yield self.tomap()
       
   129 
       
   130     def show(self, context, mapping):
       
   131         # TODO: switch gen to (context, mapping) API?
       
   132         gen = self.gen
       
   133         if callable(gen):
       
   134             return gen()
       
   135         return gen
   105 
   136 
   106 def hybriddict(data, key='key', value='value', fmt=None, gen=None):
   137 def hybriddict(data, key='key', value='value', fmt=None, gen=None):
   107     """Wrap data to support both dict-like and string-like operations"""
   138     """Wrap data to support both dict-like and string-like operations"""
   108     prefmt = pycompat.identity
   139     prefmt = pycompat.identity
   109     if fmt is None:
   140     if fmt is None:
   121     return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x))
   152     return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x))
   122 
   153 
   123 def unwraphybrid(context, mapping, thing):
   154 def unwraphybrid(context, mapping, thing):
   124     """Return an object which can be stringified possibly by using a legacy
   155     """Return an object which can be stringified possibly by using a legacy
   125     template"""
   156     template"""
   126     gen = getattr(thing, 'gen', None)
   157     if not isinstance(thing, wrapped):
   127     if gen is None:
       
   128         return thing
   158         return thing
   129     if callable(gen):
   159     return thing.show(context, mapping)
   130         return gen()
       
   131     return gen
       
   132 
   160 
   133 def unwrapvalue(thing):
   161 def unwrapvalue(thing):
   134     """Move the inner value object out of the wrapper"""
   162     """Move the inner value object out of the wrapper"""
   135     if not util.safehasattr(thing, '_value'):
   163     if not util.safehasattr(thing, '_value'):
   136         return thing
   164         return thing