equal
deleted
inserted
replaced
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 |