comparison mercurial/templater.py @ 10845:9d8194c2fcbd

templater: preparse templates and cache This breaks templates down into a list of literal and {} groups, with group types preidentified.
author Matt Mackall <mpm@selenic.com>
date Mon, 05 Apr 2010 15:25:08 -0500
parents b91c1804008e
children 594140b1e12d
comparison
equal deleted inserted replaced
10844:6722ba3bf80b 10845:9d8194c2fcbd
45 def __init__(self, loader, filters={}, defaults={}): 45 def __init__(self, loader, filters={}, defaults={}):
46 self.loader = loader 46 self.loader = loader
47 self.filters = filters 47 self.filters = filters
48 self.defaults = defaults 48 self.defaults = defaults
49 self.cache = {} 49 self.cache = {}
50 self.parsecache = {}
50 51
51 def process(self, t, map): 52 def process(self, t, map):
52 '''Perform expansion. t is name of map element to expand. map contains 53 '''Perform expansion. t is name of map element to expand. map contains
53 added elements for use during expansion. Is a generator.''' 54 added elements for use during expansion. Is a generator.'''
54 tmpl = self.loader(t) 55 if t not in self.parsecache:
55 iters = [self._process(tmpl, map)] 56 tmpl = self.loader(t)
57 self.parsecache[t] = self._parse(tmpl)
58 parsed = self.parsecache[t]
59 iters = [self._process(parsed, map)]
56 while iters: 60 while iters:
57 try: 61 try:
58 item = iters[0].next() 62 item = iters[0].next()
59 except StopIteration: 63 except StopIteration:
60 iters.pop(0) 64 iters.pop(0)
98 x = f(x) 102 x = f(x)
99 return x 103 return x
100 self.cache[expr] = apply 104 self.cache[expr] = apply
101 return self.cache[expr](get) 105 return self.cache[expr](get)
102 106
103 def _process(self, tmpl, map): 107 def _parse(self, tmpl):
108 '''preparse a template'''
109
110 parsed = []
111 pos, stop = 0, len(tmpl)
112 while pos < stop:
113 n = tmpl.find('{', pos)
114 if n < 0:
115 parsed.append(('', tmpl[pos:stop]))
116 break
117 if n > 0 and tmpl[n - 1] == '\\':
118 # escaped
119 parsed.append(('', tmpl[pos:n + 1]))
120 pos = n + 1
121 continue
122 if n > pos:
123 parsed.append(('', tmpl[pos:n]))
124
125 pos = n
126 n = tmpl.find('}', pos)
127 if n < 0:
128 # no closing
129 parsed.append(('', tmpl[pos:stop]))
130 break
131
132 expr = tmpl[pos + 1:n]
133 pos = n + 1
134
135 if '%' in expr:
136 parsed.append(('%', expr))
137 elif '|' in expr:
138 parsed.append(('|', expr))
139 else:
140 parsed.append(('g', expr))
141
142 return parsed
143
144 def _process(self, parsed, map):
104 '''Render a template. Returns a generator.''' 145 '''Render a template. Returns a generator.'''
105 146
106 def get(key): 147 def get(key):
107 v = map.get(key) 148 v = map.get(key)
108 if v is None: 149 if v is None:
109 v = self.defaults.get(key, '') 150 v = self.defaults.get(key, '')
110 if hasattr(v, '__call__'): 151 if hasattr(v, '__call__'):
111 v = v(**map) 152 v = v(**map)
112 return v 153 return v
113 154
114 pos, stop = 0, len(tmpl) 155 for t, e in parsed:
115 while pos < stop: 156 if not t:
116 n = tmpl.find('{', pos) 157 yield e
117 if n < 0: 158 elif t is '|':
118 yield tmpl[pos:stop] 159 yield self._filter(e, get, map)
119 break 160 elif t is '%':
120 if n > 0 and tmpl[n - 1] == '\\': 161 yield self._format(e, get, map)
121 # escaped 162 elif t is 'g':
122 yield tmpl[pos:n + 1] 163 yield get(e)
123 pos = n + 1
124 continue
125 if n > pos:
126 yield tmpl[pos:n]
127
128 pos = n
129 n = tmpl.find('}', pos)
130 if n < 0:
131 # no closing
132 yield tmpl[pos:stop]
133 break
134
135 expr = tmpl[pos + 1:n]
136 pos = n + 1
137
138 if '%' in expr:
139 yield self._format(expr, get, map)
140 elif '|' in expr:
141 yield self._filter(expr, get, map)
142 else:
143 yield get(expr)
144 164
145 engines = {'default': engine} 165 engines = {'default': engine}
146 166
147 class templater(object): 167 class templater(object):
148 168